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
登录接口使用:GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
拉取用户信息微信登录流程如下
获取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); // 生成token
token 只是一个key值,通过携带的token,服务器可以token向缓存文件匹配,拿到属于这个用户的信息 可参见 saveToAllValue 方法
当然,我使用的这种方法还是比较浅显,可以参见 Jwt
本文由 邓尘锋 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: May 4, 2019 at 11:39 am