180 lines
5.7 KiB
PHP
180 lines
5.7 KiB
PHP
<?php
|
||
/**
|
||
* Created by PhpStorm.
|
||
* User: Administrator
|
||
* Date: 2019/5/25 0025
|
||
* Time: 16:47
|
||
*/
|
||
|
||
namespace app\api\service;
|
||
|
||
use app\lib\exception\ParamException;
|
||
use think\Exception;
|
||
use app\api\model\User as UserModel;
|
||
use think\facade\Cache;
|
||
|
||
class UserToken extends Token
|
||
{
|
||
protected $code;
|
||
protected $wxLoginUrl;
|
||
protected $wxAppID;
|
||
protected $wxAppSecret;
|
||
|
||
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);
|
||
}
|
||
|
||
/**
|
||
* 登陆
|
||
* 思路1:每次调用登录接口都去微信刷新一次session_key,生成新的Token,不删除久的Token
|
||
* 思路2:检查Token有没有过期,没有过期则直接返回当前Token
|
||
* 思路3:重新去微信刷新session_key并删除当前Token,返回新的Token
|
||
*/
|
||
public function get($paramPost)
|
||
{
|
||
$result = curl_get($this->wxLoginUrl);
|
||
|
||
// 注意json_decode的第一个参数true
|
||
// 这将使字符串被转化为数组而非对象
|
||
|
||
$wxResult = json_decode($result, true);
|
||
|
||
if (empty($wxResult)) {
|
||
// 为什么以empty判断是否错误,这是根据微信返回
|
||
// 规则摸索出来的
|
||
// 这种情况通常是由于传入不合法的code
|
||
throw new ParamException([
|
||
'code'=>401,
|
||
'msg' => '获取session_key及openID时异常,微信内部错误',
|
||
'errorCode' => 10001
|
||
]);
|
||
}
|
||
else {
|
||
// 建议用明确的变量来表示是否成功
|
||
// 微信服务器并不会将错误标记为400,无论成功还是失败都标记成200
|
||
// 这样非常不好判断,只能使用errcode是否存在来判断
|
||
$loginFail = array_key_exists('errcode', $wxResult);
|
||
if ($loginFail) {
|
||
$this->processLoginError($wxResult);
|
||
}
|
||
else {
|
||
return $this->grantToken($wxResult,$paramPost);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// 颁发令牌
|
||
// 只要调用登陆就颁发新令牌
|
||
// 但旧的令牌依然可以使用
|
||
// 所以通常令牌的有效时间比较短
|
||
// 目前微信的express_in时间是7200秒
|
||
// 在不设置刷新令牌(refresh_token)的情况下
|
||
// 只能延迟自有token的过期时间超过7200秒(目前还无法确定,在express_in时间到期后
|
||
// 还能否进行微信支付
|
||
// 没有刷新令牌会有一个问题,就是用户的操作有可能会被突然中断
|
||
private function grantToken($wxResult)
|
||
{
|
||
// 此处生成令牌使用的是TP5自带的令牌
|
||
// 如果想要更加安全可以考虑自己生成更复杂的令牌
|
||
// 比如使用JWT并加入盐,如果不加入盐有一定的几率伪造令牌
|
||
$openid = $wxResult['openid'];
|
||
$user = UserModel::getByOpenID($openid);
|
||
if (!$user)
|
||
// 借助微信的openid作为用户标识
|
||
// 但在系统中的相关查询还是使用自己的uid
|
||
{
|
||
$uid = $this->newUser($openid);
|
||
}
|
||
else {
|
||
$uid = $user->id;
|
||
}
|
||
$cachedValue = $this->prepareCachedValue($wxResult, $uid);
|
||
$token = $this->saveToCache($cachedValue);
|
||
return $token;
|
||
}
|
||
|
||
private function newUser($openid){
|
||
$user = UserModel::create([
|
||
'openid' =>$openid
|
||
]);
|
||
return $user->id;
|
||
}
|
||
|
||
//生成token并缓存
|
||
private function saveToCache($wxResult){
|
||
|
||
$key = self::generateToken();
|
||
$value = json_encode($wxResult);
|
||
$request = Cache::store('redis')->set($key,$value,2592000);
|
||
if(!$request){
|
||
throw new ParamException([
|
||
'code' => 401,
|
||
'msg' => '服务起缓存异常',
|
||
'errorCode' => 10001
|
||
]);
|
||
}
|
||
return $key;
|
||
}
|
||
|
||
//缓存数据预处理
|
||
private function prepareCachedValue($wxResult, $uid)
|
||
{
|
||
$cachedValue = $wxResult;
|
||
$cachedValue['uid'] = $uid;
|
||
return $cachedValue;
|
||
}
|
||
|
||
|
||
|
||
private function processLoginError($wxResult){
|
||
throw new ParamException([
|
||
'msg' => $wxResult['errmsg'],
|
||
'errorCode' => $wxResult['errcode']
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 过滤微信昵称的特殊表情
|
||
* @param $text
|
||
* @param string $replaceTo
|
||
* @return null|string|string[]
|
||
*/
|
||
public function filterEmoji($text, $replaceTo = 'x'){
|
||
$clean_text = "";
|
||
// Match Emoticons
|
||
$regexEmoticons = '/[\x{1F600}-\x{1F64F}]/u';
|
||
$clean_text = preg_replace($regexEmoticons, $replaceTo, $text);
|
||
// Match Miscellaneous Symbols and Pictographs
|
||
$regexSymbols = '/[\x{1F300}-\x{1F5FF}]/u';
|
||
$clean_text = preg_replace($regexSymbols, $replaceTo, $clean_text);
|
||
// Match Transport And Map Symbols
|
||
$regexTransport = '/[\x{1F680}-\x{1F6FF}]/u';
|
||
$clean_text = preg_replace($regexTransport, $replaceTo, $clean_text);
|
||
// Match Miscellaneous Symbols
|
||
$regexMisc = '/[\x{2600}-\x{26FF}]/u';
|
||
$clean_text = preg_replace($regexMisc, $replaceTo, $clean_text);
|
||
// Match Dingbats
|
||
$regexDingbats = '/[\x{2700}-\x{27BF}]/u';
|
||
$clean_text = preg_replace($regexDingbats, $replaceTo, $clean_text);
|
||
return $clean_text;
|
||
}
|
||
|
||
/**
|
||
* 非小程序登录token
|
||
* @param $arr
|
||
* @return string
|
||
* @throws ParamException
|
||
*/
|
||
public function LoginToken($str)
|
||
{
|
||
$token = $this->saveToCache($str);
|
||
return $token;
|
||
}
|
||
|
||
} |