Oauth+thinkphp的理解与实践
Oauth+thinkphp的理解与实践
- 首先 , Oauth 是什么?
具体的可参见阮一峰的Oauth的讲解,地址,其中,阐述的大家可以看一看,我主要针对的是其中的 授权码模式。
-
授权码模式:
-
- 用户打开客户端,客户端请求用户给与授权
-
- 用户同意授权
-
- 客户端获得授权后,向认证服务器(发放授权方)申请令牌
-
- 客户端得到令牌(可以设置权限)后,就可以向自己的资源服务器拿权限范围之内的资料了
-
举个例子-我要问妈妈拿钱买零食:
首先,我要产生买零食的欲望(步骤1 ),有买零食的欲望后(2),我要和妈妈说,要妈妈同意并且给我钱,我才能买,不然妈妈会打我并且不让我买零食(3) , 我拿到钱后,只要我有足够多的钱(权限)就可以去商店随便买我卖的钱(权限范围)的零食了
授权码模式 模式是其中最复杂也是最安全的模式
- 实践
只要用过微信小程序的人,便知道,当第一次使用的时候,它总是会叫你授权。
对的,这就是授权码模式中的 行为1
这里我主要针对微信的登录流程并结合授权码模式进行实践
技术支持:thinkphp
工具支持:tool - 下载地址:
在线文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
小程序登录行为处理:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html
接口:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/code2Session.html
拉取用户信息微信登录流程如下
-
获取code,获取code
注册小程序号测试号(建议新建一个邮箱,公众号账号和小程序账号不同), 创建一个测试
打开设置->开发设置 , 保存你的AppID 和 AppSecret
打开微信开发工具,导入项目文件,启动工具 (下载地址)[]
点击申请令牌,获取code -
通过code换取网页授权access_token、openid
/**
* @return string token 辨认用户信息
* @throws CacheException
* @throws Exception
* @throws WechatException
*/
public function get()
{
// 发起一个 HTTP请求 通过code换取网页授权access_token 的行为
// 类似于: https://api.weixin.qq.com/sns/jscode2session?appid=你的appid&secret=你的SECRET&js_code=JSCODE&grant_type=authorization_code$result = curl_get($this->wxLoginUrl);
$result = json_decode($result , true);// 如果为空的话,则是微信内部出现错误了
if( empty($result) ) {
throw new Exception('获取access_token 和 oppenid时 发生异常:error,内部错误');
}else{
// 错误情况下的返回: {"errcode":40029,"errmsg":"invalid code"}
// 检查是否存在错误码
if( array_key_exists('errcode' , $result) ) {
// 处理一个异常信息,可忽略
$this->processLoginError($result);
}
}// 获取一个token
$token = $this->grantToken($result);return $token;
}
/**
* 处理流程:
* 通过openid检查数据库中是否存在这个用户,否则创建,返回当前授权用户id
* 准备缓存数据,写入$result+$uid信息,过期时间查看system配置项
* 写入缓存,返回存入缓存的key=token
* @param $uid integer 用户的id
* @param $result array 获得的微信授权后得到的信息
* @return string token 数据(存放用户信息)
* @throws CacheException 异常处理
*/
public function grantToken($result)
{
$openid = $result['openid'];
// 检查数据库中是否存在这个用户
$user = (new UserModel)->getUserOpenid($openid);// 当数据库中不存在这个 用户的时候插入用户
if( !$user ) {
$user = $this->newUser($openid);
}
$uid = $user->id;// 准备缓存数据
$cachedValue = $this->prepareCacheData($result , $uid);// 写入缓存
$token = $this->saveToAllValue($cachedValue);return $token;
}/**
* 写入缓存处理逻辑
* @param $value array $result+$uid : 缓存的信息
* @return string token
* @throws CacheException
*/
public function saveToAllValue($value) {
$key = self::generateToken(32);
$value = json_encode($value);
$expire_in = config('system.expire_in');
$result = cache($key , $value , $expire_in);
if( !$result ) {
throw new CacheException([
'msg' => '服务器缓存出现异常',
'errCode' => '30000'
]);
}
return $key;
}处理流程,当我执行get方法时,发起了一个针对 https://api.weixin.qq.com/sns/jscode2session?appid=你的appid&secret=你的SECRET&js_code=JSCODE&grant_type=authorization_code 的get 请求。
请求成功:
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}请求失败:
{"errcode":40029,"errmsg":"invalid code"}
一般除了invalid code错误之外,还会出现code已使用的情况。
记住:code 只能使用一次
-
资源服务器发放token
当取得授权后,说明你用户已经成功的加入了小程序。对用户信息进行存档
疑问:如何避免用户的权限问题呢(不能对资源服务器随意的发起任何资源请求)
每个人的信息是独一无二的,不能让其他人看到,或者需要登录查看这就需要涉及到发放资源服务器token了
资源服务器针对每个用户当前的一段时间的行为给与一个token,客户端可以携带这个token向客户端证明自己的身份来请求相关资源
设置token相关代码:
$key = randomkeys($length); // 随机一个字符串
$salt = config('system.token_salt'); // 加盐
$time = $_SERVER['REQUEST_TIME_FLOAT']; // 当前请求时间(防止token重复)
return md5($key . $salt . $time); // 生成tokentoken 只是一个key值,通过携带的token,服务器可以token向缓存文件匹配,拿到属于这个用户的信息 可参见 saveToAllValue 方法
当然,我使用的这种方法还是比较浅显,可以参见 Jwt

浙公网安备 33010602011771号