微信小程序登录换取token的教程


Posted in Javascript onMay 31, 2018

前言:

这次主要是介绍些业务逻辑,技术点倒是没有多少。不过在开发中,优秀的编程思路同样是非常值得学习的。

最近小程序可以说在开发届狠狠的火了一把。微信小程序可以开发游戏,腾讯率先带头,做出了一个跳一跳也是点爆朋友圈。所谓落后就要挨打,那么今天就开始学习小程序的一些小知识吧(本文基于十年磨一剑的tp5)

目录:

  1. 微信登录换取token的流程
  2. 如何将code变成openid和session_key
  3. 抛出错误异常和派发令牌

一:微信登录换取token的流程

多说无益,直接上图

微信小程序登录换取token的教程

小程序获取token.png

这里介绍的主要是后端开发的流程,前端的不是本文介绍的重点

二:如何将code变成openid和session_key

我们后端开发人员对这个业务是从接受code开始的,由客户端发来一个code码。

我们接受后先进行验证

//创建独立验证器,调用验证器中的验证方法
TokenCheck::instance()->goCheck();

如果不是很清楚验证器的用法的朋友 可以先看看我之前写的验证器的使用

验证规则很简单,就是判断不为空就可以了

下一步就是我们需要把code换取openid 和session_key了

首先我们需要在创建一个service层的类,(为什么要使用service层呢?主要是我为了让模型层粒度细一些。业务比较复杂的就放在service层。这样比较利于后期修改和升级)

class UserToken extends Token
{
  protected $wxAppId;
  protected $wxAppSecret;
  protected $wxLoginUrl;

  //构造函数中赋值成员变量
  public function __construct($code)
  {
    $this->wxAppId = config('wx.app_id');
    $this->wxAppSecret = config('wx.app_secret');
    $this->wxLoginUrl = sprintf(config('wx.login_url'), $this->wxAppId, $this->wxAppSecret, $code);
  }
}

写一个构造函数,让在对象生成的时候就赋值成员变量方便使用,这里的appid和appsecret 都是在微信申请小程序的时候就有了的。这里就不介绍了。之前我是把他们全部存在我的配置文件的。使用tp5提供的config函数将他们提出来。最后使用 sprintf方法,将这些参数拼接到wxLoginUrl中,方便我们访问。

熟悉Oauth2.0的朋友都知道,拿到这个url其实就是微信的一个接口,我们去换取授权。

下面我们创建一个getUserToken方法

/**
   * 获取用户的令牌方法
   * @throws Exception
   */
  public function getUserToken()
  {
    //调用公共函数中的http方法(也就是curl的方法,我也是在网上抄的。存放在common.php中就可以直接用了)
    $result = http($this->wxLoginUrl, 'post');
    //判断连接是否成功
    if ($result[0] == 200) {
      //将返回的json处理成数组
      $wxResult = json_decode($result[1], true);
      //判空
      if (empty($wxResult)) {
        throw new Exception('获取session_key,openID时异常,微信内部错误');
      } else {
         //判断返回的结果中是否有错误码
        if (isset($wxResult['errcode'])) {
          //如果有错误码,调用抛出错误方法
          $this->_throwWxError($wxResult);
        } else {
          //没有错误码,调用私有的派发token方法
          $token = $this->_grantToken($wxResult);
          return $token;
        }
      }
    } else {
      throw new Exception('连接微信服务器失败');
    }
  }

写好了,方法之后,只需要在控制器中调用这个getUserToken方法就可以了。

大家可能会问,那个_throwWxError和_grantToken方法是干什么的?

可能大家也看出来了,这个getUserToken方法中我们一个获取到了微信返回的结果,也就是$wxResult变量中的数据。如果不出别的意外那么,里面就有我们需要的openid和session_key。这不过,介绍到这里,我们还没有开始使用他们

三:抛出错误异常和派发令牌

这里两个其实就是两个方法,重点是派发令牌。这里的抛出异常。我准备单独写一次介绍。

/**
   * 微信获取open_id失败,抛出异常方法
   * @param $wxResult
   * @throws WxException
   */
  private function _throwWxError($wxResult)
  {
    throw new WxException(
      [
        'message' => $wxResult['errmsg'],
        'errorCode' => $wxResult['errcode']
      ]
    );
  }

我们来看_grantToken方法

我们将微信返回给我们的数据,转换为数组后,保存到$wxResult中,在调用派发令牌方法时,直接传入。

下面的代码中有个User类调用的getUidByOpenId方法,这里是User模型上封装的一个查询方法,就是看User表中是否有这个openid,如果有返回uid

如果数据库中没有uid的话,说明是新用户,则在数据库中插入一条数据,返回新插入的主键 id

/**
   * 派发User 令牌
   * @param $wxResult
   * @return string
   * @throws Exception
   */
  private function _grantToken($wxResult)
  {
    //拿到open_id
    $openId = $wxResult['openid'];
    //判断open_id是否存在
    $id = User::getUidByOpenId($openId);
    //如果数据库中不存在
    if (!$id) {
      //添加一条记录,返回新创建的id
      $id = User::createUser($openId);
      if (!$id) {
        throw new Exception('新增一条User失败');
      }
    }
    //拼接数据为一个数组。(这个方法就是将wxResult中的openid和session_key取出,然后和用户id一起放进一个数组)
    $tokenValue = $this->_splicingValue($wxResult, $id);
    //制作令牌
    //存入缓存
    $token = $this->_saveCache($tokenValue);
    //返回token
    return $token;
  }

下面我们来看看_saveCache方法

我们将拼接成一个数组的数据$tokenValue直接传入方法中,调用一个随机字符串方法,将这个随机字符串当做key,把传入我用户数据序列化之后当作value,然后根据配置里的缓存过期时间,来存入缓存。

/**
   * 将令牌存入缓存,返回token
   * @param $tokenValue
   * @return string
   * @throws TokenException
   */
  private function _saveCache($tokenValue)
  {
    //调用父类中的随机字符串方法
    $key = parent::_makeToken();
    //序列化包含id,openid,sessionKey的数组
    $value = serialize($tokenValue);
    //在配置中取出保存时间的配置
    $expriesTime = config('setting.expires_in');
    //存入缓存
    $result = cache($key, $value, $expriesTime);
    //如果存入失败,抛出异常
    if (!$result) {
      throw new TokenException(
        ['errorCode' => 10003, 'message' => 'Token save fail']
      );
    }
    //返回随机字符串(也就是要返回给客户端的token)
    return $key;
  }

随机字符方法,为了提高token的安全性,让别人不那么容易的复制我们的token。我就写了这样的一个方法,大家如果有安全性更好的方法也可以使用自己想的。我就不介绍了 看代码吧

/**
   * 构建token随机字符串
   */
  public function _makeToken()
  {
    //随机抽取32位字符串方法,保存在common.php中
    $randChar = randomkeys(32);
    //时间戳
    $timestamp = time();
    //配置中的盐值
    $salt = config('secret.token_salt');
    //拼接之后sha1加密
    return sha1($randChar . $timestamp . $salt);
  }

这里我们就将随机生成的随机字符串返回到service层,service层再返回给控制器,控制器就可以返回给客户端了

看下完整的控制器吧

public function getToken($code = '')
  {
    //创建独立验证器,调用验证器中的验证方法
    TokenCheck::instance()->goCheck();
    $utObj = new UserToken($code);
    $token = $utObj->getUserToken();
    return ['token'=>$token];
  }

这样一个小程序登录换取token的流程就走完了。这个业务呢是借助微信服务器中的openid来作为唯一标识来派发token,如果不是微信的项目的话,我们同样的可以是微博登录,qq登录等第三方登录。或者自己的数据库中的id来作为唯一标识。同样可以派发token。

这里只是介绍了token的派发,还有一些token的应用,有时间的时候再写吧。今天就介绍到这里。如果有什么没有写对的地方,希望大神指正,我们共同学习。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
学习ExtJS form布局
Oct 08 Javascript
js function使用心得
May 10 Javascript
js对象与打印对象分析比较
Apr 23 Javascript
js Select下拉列表框进行多选、移除、交换内容的具体实现方法
Aug 13 Javascript
删除javascript所创建子节点的方法
May 21 Javascript
javascript编程异常处理实例小结
Nov 30 Javascript
JS控件bootstrap suggest plugin使用方法详解
Mar 25 Javascript
基于zepto.js实现登录界面
Oct 09 Javascript
解决bootstrap模态框数据缓存的问题方法
Aug 10 Javascript
详解React native fetch遇到的坑
Aug 30 Javascript
vue监听dom大小改变案例
Jul 29 Javascript
基于Vue全局组件与局部组件的区别说明
Aug 11 Javascript
Rollup处理并打包JS文件项目实例代码
May 31 #Javascript
手把手教你vue-cli单页到多页应用的方法
May 31 #Javascript
详解基于Node.js的HTTP/2 Server实践
May 31 #Javascript
jQuery基于Ajax实现读取XML数据功能示例
May 31 #jQuery
jQuery实现动态加载select下拉列表项功能示例
May 31 #jQuery
vuejs实现标签选项卡动态更改css样式的方法
May 31 #Javascript
Vue组件之极简的地址选择器的实现
May 31 #Javascript
You might like
PHP调用三种数据库的方法(1)
2006/10/09 PHP
php microtime获取浮点的时间戳
2010/02/21 PHP
基于PHP magic_quotes_gpc的使用方法详解
2013/06/24 PHP
PHP实现文件下载详解
2014/11/27 PHP
php限制ip地址范围的方法
2015/03/31 PHP
详解 PHP加密解密字符串函数附源码下载
2015/12/18 PHP
js 一个关于图片onload加载的事
2013/11/10 Javascript
基于jquery的simpleValidate简易验证插件
2014/01/31 Javascript
jquery的ajax简单结构示例代码
2014/02/17 Javascript
IE中的File域无法清空使用jQuery重设File域
2014/04/24 Javascript
基于NodeJS的前后端分离的思考与实践(三)轻量级的接口配置建模框架
2014/09/26 NodeJs
使用jquery组件qrcode生成二维码及应用指南
2015/02/22 Javascript
基于javascript实现图片滑动效果
2016/05/07 Javascript
iscroll碰到Select无法选择下拉刷新的解决办法
2016/05/21 Javascript
JS基于构造函数实现的菜单滑动显隐效果【测试可用】
2016/06/21 Javascript
Angularjs的ng-repeat中去除重复数据的方法
2016/08/05 Javascript
分分钟玩转Vue.js组件
2016/10/25 Javascript
微信小程序显示下拉列表功能【附源码下载】
2017/12/12 Javascript
关于react-router/react-router-dom v4 history不能访问问题的解决
2018/01/08 Javascript
vue2 中二级路由高亮问题及配置方法
2019/06/10 Javascript
vue+eslint+vscode配置教程
2019/08/09 Javascript
微信小程序 简易计算器实现代码实例
2019/09/02 Javascript
vue实现数据控制视图的原理解析
2020/01/07 Javascript
Javascript中Math.max和Math.max.apply的区别和用法详解
2020/08/24 Javascript
使用Python实现简单的服务器功能
2017/08/25 Python
python opencv 读取本地视频文件 修改ffmpeg的方法
2019/01/26 Python
python3.6+django2.0+mysql搭建网站过程详解
2019/07/24 Python
Python学习笔记之文件的读写操作实例分析
2019/08/07 Python
AJAX的全称是什么
2012/11/06 面试题
教师的实习自我鉴定
2013/12/17 职场文书
秋天的雨教学反思
2014/04/27 职场文书
行政求职信
2014/07/04 职场文书
国家税务局领导班子对照检查材料思想汇报
2014/10/04 职场文书
求职自荐信怎么写
2015/03/04 职场文书
考勤制度通知
2015/04/25 职场文书
分享一个vue实现的记事本功能案例
2022/04/11 Vue.js