关于微信的登录以及PHP后台的实现

一、前言

   这篇文章所学到来自七月的小程序教学,同时我也是为了再次巩固下对微信的登录以及PHP后台生成的token的过程。以下是我的感受和心得。

二、准备

  1.微信小程序的appID,appKey(app_secret)用来对微信服务器获取用户的openId以及其他信息。
  2.后台使用到Tp5框架。
  3.MySQL数据库。

三、思考

微信登录的流程图
1.在微信的开发者文档中向我们介绍了微信登录的流程图,让我们先来解读一下这个

  1. 在小程序的内部,会通过wx.login()获取code码 ,同时将获取到的code码发送到后台。
  2. 接下来,开发者服务器也就是你的后台,将从前台获取的code码加上你的appid+appsecret拼接成一个url去向微信服务器获取到seeion_key以及用户的openid等。
  3. 在后台,我们将用获取到的用户信息,同时生成token(自定义登录令牌),将token和用户的信息存入在缓存之中,方便用户获取服务时的身份确认。
  4. 此时后台仅仅将token信息返回到微信小程序,切记不能够暴露用户的openid以及其他信息,
  5. 微信小程序端,将获取的token保存在本地。
  6. 在接下来的一些需要用户身份的请求中,都要携带token去请求后台。
  7. 后台获取到微信小程序端传来的token,读取缓存,拿到用户的openid,在进行相关的业务逻辑

四、code

  1. 关于3-1中,微信小程序端如何获取code,并向后台发起请求。
wx.login({
      success: function(res) {
        var code = res.code;  //通过回调函数获取code
        wx.request({  //向后台发起请求  POST 
          url: 'index.php',
          data: {
            code: code
          },
          method: 'POST',
          success: function(res) {
          //TODO
          },
          fail: function(res) {
           //TODO
          }
        })
      },
      fail: function(res) {
        //TODO
      }
    })
  1. 3-2 后台部分代码
    1)首先建立一个配置文件wx.php
return [
    'app_id' => '你的appid',
    'app_secret' => '你的appkey(app_secret)',
    'login_url' => 'https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code',]

2)接下来在controller中建立类文件Token.php

namespace app\api\controller\v1;

use app\api\service\UserToken;
use app\api\validate\TokenGet;

class Token
{
//自己设置路由,这是获取到微信小程序端向后台发送的code
    public function getToken($code='')
    {
    //这一步是验证参数
        (new TokenGet())->goCheck();
        //获取token
        $ut = new UserToken($code);
        $token = $ut->get();
        //向微信小程序端返回token
        return [
            'token'=>$token
        ];

    }

}

3)新建一个service文件夹,首先建立UserToken.php,这一步的主题思路就是,要将获取的code拿来,拼接上自己的appid和appkey去先微信服务器获取用户的信息,并且同时生成随机字符串,存入缓存中。

<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/10/9
 * Time: 13:28
 */

namespace app\api\service;

use app\lib\exception\TokenException;
use app\lib\exception\WeChatException;
use think\Exception;
use app\api\model\User;
class UserToken extends Token
{
    protected $code;
    protected $wxAppID;
    protected $wxAppSecret;
    protected $wxLoginUrl;
//从配置文件导入个人信息
    function __construct($code)
    {
        $this->code = $code;
        $this->wxAppID = config('wx.app_id');
        $this->wxAppSecret = config('wx.app_secret');
        $this->wxLoginUrl = sprintf(config('wx.login_url'),$this->wxAppID,$this->wxAppSecret,$this->code);
    }
    public function get(){
    //curl_get是一个请求方法,通过url去请求,这个方法我会放在最后
       $result =  curl_get($this->wxLoginUrl);
       $wxResult = json_decode($result,true);
       if (empty($wxResult)){
           throw new Exception('获取session_key以及open_id时异常,微信内部错误');
       }else{
           $loginFail = array_key_exists('errcode',$wxResult);
           if ($loginFail){
                 $this->processLoginError($wxResult);
           }else{
                return $this->grantToken($wxResult);
           }
       }
    }

    private function grantToken($wxResult){
        //拿到open_id
        //在数据库查看,这个open_id是否存在
        //在、不在新增记录
        //生成令牌 准备的缓存数据 写入缓存
        //把令牌返回去
        //key:令牌
        //value:wxResult uid scope
        $openid = $wxResult['openid'];
        $user = User::getByOpenID($openid);
        if (!$user){
            $uid = $this->newUser($openid);
        }else{
            $uid = $user->id;
        }
        $cachedValue = $this->prepareCachedValue($wxResult,$uid);
        $token = $this->saveToCache($cachedValue);
        return $token;
    }
    //写缓存,key = token   value = user 
    private function saveToCache($wxRequest){
        $key = self::generateToken();
        $value = json_encode($wxRequest);
        $expire_in = config('setting.token_expire_in');
        //$expire_in 表示token的有效时间  我卸载配置中了,也可以直接设置
        $result = cache($key,$value,$expire_in);
        if (!$result){
            throw new TokenException([
                'msg' => '服务器缓存异常',
                'errorCode' => 10005,
            ]);
        }
        return $key;
    }
   //缓存写入前的准备,写入权限信息,以后可以通过不同权限来访问不同的接口
    private function prepareCachedValue($wxResult,$uid){

        $cachedValue = $wxResult;
        $cachedValue['uid'] = $uid;
        //scope=16 代表App用户的权限数值 ScopeEnum后面给出
        $cachedValue['scope'] = \ScopeEnum::User;
        return $cachedValue;

    }
    //利用model层,创建一个新用户
    private function newUser($openid){
        $user = User::create([
            'openid' => $openid
        ]);
        return $user->id;
    }

    private function processLoginError($wxResult){
        throw new WeChatException([
            'msg' =>$wxResult['error msg'],
            'errorCode' => $wxResult['error code']
        ]);
    }

}

4)token的生成,新建Token.php文件,代码如下:

<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/10/9
 * Time: 16:15
 */

namespace app\api\service;


use app\lib\exception\TokenException;
use think\Cache;
use think\Exception;
use think\Request;

class Token
{
    public static function generateToken(){
        //32个字符组成   getRandChars随机字符串,后面会给出  公共方法
        $randChars = getRandChars(32);
        //md5加密
        $timestamp = $_SERVER['REQUEST_TIME'];
        //salt盐
        $salt = config('secure.token_salt');
        return md5($randChars.$timestamp.$salt);
    }
 }

5)公共的方法

<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 流年 <[email protected]>
// +----------------------------------------------------------------------

// 应用公共文件
/**
 *
 */
function curl_get($url, &$httpCode = 0){
    $ch = curl_init();
    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);

    curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
    curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,10);
    $file_contents = curl_exec($ch);
    $httpCode = curl_getinfo($ch,CURLINFO_HTTP_CODE);
    curl_close($ch);
    return $file_contents;

}
function getRandChars($length){
    $str = null;
    $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
    $max = strlen($strPol)-1;
    for ($i = 0; $i<$length;$i++){
        $str.=$strPol[rand(0,$max)];
    }
    return $str;
}

6)tp5目录
tp5目录

五、个人总结

 其实也没啥总结,就是要在分析代码的需求上,逻辑要更紧密,多看看大佬的代码,提升思维的方向。还有,多撸哦O(∩_∩)O哈哈~。
发布了9 篇原创文章 · 获赞 3 · 访问量 445

猜你喜欢

转载自blog.csdn.net/qq_41740808/article/details/83864583
今日推荐