Oauth+thinkphp的理解与实践

Oauth+thinkphp的理解与实践

  1. 首先 , Oauth 是什么?

具体的可参见阮一峰的Oauth的讲解,地址,其中,阐述的大家可以看一看,我主要针对的是其中的 授权码模式。

  • 授权码模式:

      1. 用户打开客户端,客户端请求用户给与授权
      1. 用户同意授权
      1. 客户端获得授权后,向认证服务器(发放授权方)申请令牌
      1. 客户端得到令牌(可以设置权限)后,就可以向自己的资源服务器拿权限范围之内的资料了

举个例子-我要问妈妈拿钱买零食:

首先,我要产生买零食的欲望(步骤1 ),有买零食的欲望后(2),我要和妈妈说,要妈妈同意并且给我钱,我才能买,不然妈妈会打我并且不让我买零食(3) , 我拿到钱后,只要我有足够多的钱(权限)就可以去商店随便买我卖的钱(权限范围)的零食了

授权码模式 模式是其中最复杂也是最安全的模式

  1. 实践

只要用过微信小程序的人,便知道,当第一次使用的时候,它总是会叫你授权。
对的,这就是授权码模式中的 行为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

原文: http://surest.cn/article/44

posted @ 2018-10-19 01:32  mysure  阅读(678)  评论(0)    收藏  举报