创建一个登录接口
相关知识
简单的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;
}