我发现,你在我心中的位置会膨胀。
小程序端获取code
1 2 3 4 5 6
| wx.login({ success: function (login_res) { if (login_res.code) { console.log("微信登录请求返回code:" + login_res.code);
......
|
带上code访问服务器接口
服务器接口根据code获取Token
路由设计
1
| Route::post('api/:version/token/user', 'api/:version.Tokens/getToken');
|
控制器方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php
namespace app\api\controller\v1;
use app\api\service\UserToken; use app\api\validate\TokenGet;
class Tokens { public function getToken($code) { (new TokenGet())->goCheck(); $ut = new UserToken($code); $token = $ut->get(); return ['token' => $token]; } }
|
Service服务方法
tp5\application\api\service\UserToken.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
| <?php
namespace app\api\service;
use app\api\model\User; use app\lib\enum\ScopeEnum; use app\lib\exception\TokenException; use app\lib\exception\WeChatException; use think\Exception;
class UserToken extends Token {
protected $code; protected $wxLoginUrl; protected $wxAppID; protected $wxAppSecret;
public 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() { $res = curl_get($this->wxLoginUrl); $wxResult = json_decode($res, true); if (empty($wxResult)) { throw new Exception('微信内部错误'); } else { $loginFail = array_key_exists('errcode', $wxResult); if ($loginFail) { $this->processLoginError($wxResult); } else { return $this->grantToken($wxResult); } } }
private function grantToken($wxResult) { $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; }
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; }
private function prepareCachedValue($wxResult, $uid) { $cachedValue = $wxResult; $cachedValue['uid'] = $uid; $cachedValue['scope'] = ScopeEnum::User; return $cachedValue; }
private function newUser($openid) { $user = User::create(['openid' => $openid]); return $user->id; }
private function processLoginError($wxResult) { throw new WeChatException( [ 'msg' => $wxResult['errmsg'], 'errorCode' => $wxResult['errcode'] ]); } }
|
生成token函数
1 2 3 4 5 6 7 8
| public static function generateToken() { $randChar = getRandChar(32); $timestamp = $_SERVER['REQUEST_TIME_FLOAT']; $tokenSalt = config('secure.token_salt'); return md5($randChar . $timestamp . $tokenSalt); }
|
接口返回
接口正确返回token, 我们需要存储在客户端,以后的每次请求, 都需要在header头中带上token信息
1 2 3 4
| wx.setStorage({ key:"token", data:"value" })
|
请求新的接口
- 接口地址
http://tp5.me/api/v1/order
- 请求方式
POST
- 请求参数
header头信息1
| {"token" : "b19d0f4e05a6f3898d52b5d181a867da"}
|
body参数信息1 2 3 4 5 6
| { "products": [ {"product_id": 1, "count": 1}, {"product_id": 2, "count": 1} ] }
|
接口权限验证
我们使用ThinkPHP 5 的前置方法
在下单前检测用户的身份权限
tp5\application\api\controller\v1\Orders.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Orders extends BaseController { protected $beforeActionList = [ 'checkExclusiveScope' => ['only' => 'placeOrder'] ];
public function placeOrder() { (new OrderPlace())->goCheck(); $products = input('post.products/a'); $uid = Token::getCurrentUid(); $order = new OrderService(); $status = $order->place($uid, $products); return $status; }
|
tp5\application\api\controller\BaseController.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <?php
namespace app\api\controller;
use app\api\service\Token; use think\Controller;
class BaseController extends Controller {
protected function checkExclusiveScope() { Token::needExclusiveScope(); }
protected function checkPrimaryScope() { Token::needPrimaryScope(); }
protected function checkSuperScope() { Token::needSuperScope(); } }
|
tp5\application\api\service\Token.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
| <?php
namespace app\api\service;
use app\lib\enum\ScopeEnum; use app\lib\exception\ForbiddenException; use app\lib\exception\ParameterException; use app\lib\exception\TokenException; use think\Cache; use think\Exception; use think\Request;
class Token {
public static function generateToken() { $randChar = getRandChar(32); $timestamp = $_SERVER['REQUEST_TIME_FLOAT']; $tokenSalt = config('secure.token_salt'); return md5($randChar . $timestamp . $tokenSalt); }
public static function getCurrentTokenVar($key) { $token = Request::instance()->header('token');
$vars = Cache::get($token);
if (!$vars) { throw new TokenException(); } else { if(!is_array($vars)) { $vars = json_decode($vars, true); }
if (array_key_exists($key, $vars)) { return $vars[$key]; } else{ throw new Exception('尝试获取的Token变量并不存在'); } } }
public static function getCurrentUid() { $uid = self::getCurrentTokenVar('uid');
$scope = self::getCurrentTokenVar('scope');
if ($scope == ScopeEnum::Super) { $userID = input('get.uid'); if (!$userID) { throw new ParameterException( [ 'msg' => '没有指定需要操作的用户对象' ]); } return $userID; } else { return $uid; } }
public static function needPrimaryScope() { $scope = self::getCurrentTokenVar('scope'); if ($scope) { if ($scope >= ScopeEnum::User) { return true; } else{ throw new ForbiddenException(); } } else { throw new TokenException(); } }
public static function needExclusiveScope() { $scope = self::getCurrentTokenVar('scope'); if ($scope ){ if ($scope == ScopeEnum::User) { return true; } else { throw new ForbiddenException(); } } else { throw new TokenException(); } }
public static function needSuperScope() { $scope = self::getCurrentTokenVar('scope'); if ($scope){ if ($scope == ScopeEnum::Super) { return true; } else { throw new ForbiddenException(); } } else { throw new TokenException(); } } }
|