微信小程序登录换取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 相关文章推荐
javascript 去字符串空格终极版(支持utf8)
Nov 14 Javascript
原生javascript兼容性测试实例
Jul 01 Javascript
javascript实现简单的全选和反选功能
Jan 05 Javascript
JavaScript中创建对象的模式汇总
Apr 19 Javascript
BootStrap智能表单实战系列(十一)级联下拉的支持
Jun 13 Javascript
火狐和ie下获取javascript 获取event的方法(推荐)
Nov 26 Javascript
Bootstrap入门教程一Hello Bootstrap初识
Mar 02 Javascript
js 概率计算(简单版)
Sep 12 Javascript
简单谈谈vue的过渡动画(推荐)
Oct 11 Javascript
利用js给datalist或select动态添加option选项的方法
Jan 25 Javascript
关于layui导航栏不展示下拉列表的解决方法
Sep 25 Javascript
js调用网络摄像头的方法
Dec 05 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之第十天
2006/10/09 PHP
php二分法在IP地址查询中的应用
2008/08/12 PHP
php 什么是PEAR?(第二篇)
2009/03/19 PHP
PHP投票系统防刷票判断流程分析
2012/02/04 PHP
为百度UE编辑器上传图片添加水印功能
2015/04/16 PHP
PHP自定义图片缩放函数实现等比例不失真缩放的方法
2016/08/19 PHP
javascript setTimeout和setInterval 的区别
2009/12/08 Javascript
基于JavaScript实现继承机制之构造函数+原型链混合方式的使用详解
2013/05/07 Javascript
js获取url中指定参数值的示例代码
2013/12/14 Javascript
js实现获取div坐标的方法
2015/11/16 Javascript
浅谈JavaScript 执行环境、作用域及垃圾回收
2016/05/31 Javascript
jQuery插件jquery.kxbdmarquee.js实现无缝滚动效果
2017/02/15 Javascript
Angular.js通过自定义指令directive实现滑块滑动效果
2017/10/13 Javascript
JavaScript使用递归和循环实现阶乘的实例代码
2018/08/28 Javascript
vue-cli2.0转3.0之项目搭建的详细步骤
2018/12/11 Javascript
vue实现微信二次分享以及自定义分享的示例
2019/03/20 Javascript
vue自定义指令实现仅支持输入数字和浮点型的示例
2019/10/30 Javascript
原生js+css实现tab切换功能
2020/09/17 Javascript
[01:28:24]NAVI vs VG Supermajor 败者组 BO3 第三场 6.5
2018/06/06 DOTA
[01:02:38]DOTA2-DPC中国联赛定级赛 LBZS vs Phoenix BO3第二场 1月10日
2021/03/11 DOTA
python利用hook技术破解https的实例代码
2013/03/25 Python
python中cPickle用法例子分享
2014/01/03 Python
Python复制文件操作实例详解
2015/11/10 Python
python 链接和操作 memcache方法
2017/03/04 Python
Python实现XML文件解析的示例代码
2018/02/05 Python
django-orm F对象的使用 按照两个字段的和,乘积排序实例
2020/05/18 Python
Python中socket网络通信是干嘛的
2020/05/27 Python
华为的Java面试题
2014/03/07 面试题
三年级数学教学反思
2014/01/31 职场文书
新农村建设典型材料
2014/05/31 职场文书
群众路线自查自纠工作情况报告
2014/10/28 职场文书
写给孩子的新学期寄语
2015/02/27 职场文书
2015年秋季运动会广播稿
2015/08/19 职场文书
2016三八妇女节校园广播稿
2015/12/17 职场文书
复制别人的成功真的会成功吗?
2019/10/17 职场文书
Nginx使用X-Accel-Redirect实现静态文件下载的统计、鉴权、防盗链、限速等
2021/04/04 Servers