全栈微信小程序商城 学习笔记9.1 新建登录接口

创建一个登录接口

相关知识

简单的MVC就够了吗?浅谈Service、DAO层的引入 | 博客水木

小程序登录流程

相关表字段一览

user表

id	
openid	
nickname	
extend	
delete_time	
create_time	注册时间
update_time

准备工作

application oute.php,省略部分代码

Route::post('api/:version/token/user', 'api/:version.Token/getToken');

参数校验
applicationapivalidateTokenGet.php

<?php
namespace appapivalidate;


class TokenGet extends BaseValidate
{
    protected $rule = [
        'code' => 'require|isNotEmpty'
    ];
    protected $message = [
        'code' => '没有code,不给你获取token'
    ];
}

applicationapivalidateBaseValidate.php,省略部分代码

<?php
class BaseValidate extends Validate
{
    //...
    protected function isNotEmpty($value) {
        if (empty($value)) {
            return false;
        } else {
            return true;
        }
    }
}

异常处理

applicationlibexceptionWeChatException.php

<?php


namespace applibexception;


class WeChatException extends BaseException
{
    public $code = 400;
    public $msg = 'wechat unknown error';
    public $errorCode = 999;
}

登录配置文件

applicationextrawx.php

<?php
return [
    'app_id' => 'your app_id',
    'app_secret' => 'your appsecret',
    'login_url' => "https://api.weixin.qq.com/sns/jscode2session?" .
        "appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"
];

封装http请求

applicationapicommon.php

<?php
function curl_get($url, &$httpCode = 0)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    //不做证书校验,部署在linux环境下请改为true
    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;
}

UserToken服务层

applicationapiserviceUserToken.php

<?php


namespace appapiservice;

class UserToken
{
    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() {
        
    }
}

Token控制器

applicationapicontrollerv1Token.php

<?php


namespace appapicontrollerv1;


use appapiserviceUserToken;
use appapivalidateTokenGet;

class Token
{
    public function getToken($code = '') {
        (new TokenGet())->goCheck();
        $ut = new UserToken($code);
        $token = $ut->get($code);
        return [
            'token' => $token
        ];
    }
}

User模型

applicationapimodelUser.php

<?php


namespace appapimodel;


class User extends BaseModel
{
    // 根据openid获取uid
    public static function getByOpenID($openid) {
        $user = User::where('openid', '=', $openid)->find();
        return $user;
    }
}

UserToken服务层

<?php


namespace appapiservice;

use applibexceptionWeChatException;
use thinkException;
use appapimodelUser as UserModel;

class UserToken
{
    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() {
        // 调用微信登录接口
        $result = curl_get($this->wxLoginUrl);
        // 将返回的结果字符串转成数组
        $wxResult = json_decode($result, true);
        if (empty($wxResult)) {
            // 返回的空结果,通常因为传入不合法的code导致
            // 使用框架的异常处理,将错误记录日志
            throw new Exception('获取session_key及openID时异常,微信内部错误');
        } else {
            $loginFail = array_key_exists('errcode', $wxResult);
            if ($loginFail) {
                // 返回结果带有错误码,使用自己定义的异常类
                $this->processLoginError($wxResult);
            } else {
                return $this->grantToken($wxResult);
            }
        }
    }
    private function processLoginError($wxResult){
        throw new WeChatException([
            'msg' => $wxResult['errmsg'],
            'errorCode' => $wxResult['errcode']
        ]);
    }
    // 返回一个token
    private function grantToken($wxResult) {
        $openid = $wxResult['openid'];
        $user = UserModel::getByOpenID($openid);
        if ($user) {
            $uid = $user->id;
        } else {
            // 用户不存在
            $uid = $this->newUser($openid);
        }
        // 后续操作...
    }
    // 创建新用户
    private function newUser($openid) {
        $user = UserModel::create([
            'openid' => $openid
        ]);
        return $user->id;
    }
}

Token服务层

applicationapiserviceToken.php

<?php


namespace appapiservice;


class Token
{
    public static function generateToken() {
        $randChar = getRandChar(32);
        $timestamp = $_SERVER['REQUEST_TIME_FLOAT'];
        $tokenSalt = config('secure.token_salt');
        return md5($randChar.$timestamp.$tokenSalt);
    }
}

获取随机字符串

applicationapicommon.php

<?php
//..
function getRandChar($length) {
    //参数:随机字符串的长度
    $str = null;
    $strPol = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
    $max = strlen($strPol) - 1;
    for ($i = 0; $i < $length; $i++) {
        $str .= $strPol[rand(0, $max)];
    }
    return $str;
}

敏感信息配置

applicationextrasecure.php

<?php
return [
    //salt 盐,特殊加密信息
    'token_salt' => 'your salt'
];

token缓存时间

applicationextrasetting.php

<?php
return [
    //..
    'token_expire_in' => '7200'
];

UserToken服务层

applicationapiserviceUserToken.php,省略部分代码

<?php


namespace appapiservice;

use applibexceptionTokenException;
use applibexceptionWeChatException;
use thinkException;
use appapimodelUser as UserModel;

class UserToken extends Token
{
    // ...
    private function grantToken($wxResult) {
        $openid = $wxResult['openid'];
        $user = UserModel::getByOpenID($openid);
        if ($user) {
            $uid = $user->id;
        } else {
            $uid = $this->newUser($openid);
        }
        $cachedValue = $this->prepareCachedValue($wxResult, $uid);
        $token = $this->saveToCache($cachedValue);
        return $token;
    }
    // 组装缓存对象,scope代表用户权限
    private function prepareCachedValue($wxResult, $uid) {
        $cachedValue = $wxResult;
        $cachedValue['uid'] = $uid;
        $cachedValue['scope'] = 16;
        return $cachedValue;
    }
    // 将数据缓存并返回token用于对缓存数据的访问
    private function saveToCache($wxResult) {
        $key = self::generateToken();
        $value = json_encode($wxResult);
        $expire_in = config('setting.token_expire_in');
        $result = cache($key, $value, $expire_in);
        if (!$result) {
            throw new TokenException([
                'msg' => '服务器缓存异常',
                'errorCode' => 10005
            ]);
        }
        return $key;
    }
}

applicationlibexceptionTokenException.php

<?php


namespace applibexception;


class TokenException extends BaseException
{
    public $code = 401;
    public $msg = 'Token已过期或无效Token';
    public $errorCode = 10001;
}

测试

原文地址:https://www.cnblogs.com/Qyhg/p/14781024.html