理解oauth2.0 & 微信网页授权实现实例

时间:2024-03-01 18:43:25

关于oauth2.0

OAuth 2.0授权框架支持第三方支持访问有限的HTTP服务,通过在资源所有者和HTTP服务之间进行一个批准交互来代表资源者去访问这些资源,或者通过允许第三方应用程序以自己的名义获取访问权限。

为了方便理解,可以想象OAuth2.0就是在用户资源和第三方应用之间的一个中间层,它把资源和第三方应用隔开,使得第三方应用无法直接访问资源,从而起到保护资源的作用。

为了访问这种受保护的资源,第三方应用(客户端)在访问的时候需要提供凭证。即,需要告诉OAuth2.0你是谁你要做什么。

OAuth定义了四种角色:

  • resource owner(资源所有者)
  • resource server(资源服务器)
  • client(客户端):代表资源所有者并且经过所有者授权去访问受保护的资源的应用程序
  • authorization server(授权服务器):在成功验证资源所有者并获得授权后向客户端发出访问令牌

 

抽象的OAuth2.0流程如图所示:

  1. (A)  客户端向资源所有者请求其授权
  2. (B)  客户端收到资源所有者的授权许可,这个授权许可是一个代表资源所有者授权的凭据
  3. (C)  客户端向授权服务器请求访问令牌,并出示授权许可
  4. (D)  授权服务器对客户端身份进行认证,并校验授权许可,如果都是有效的,则发放访问令牌
  5. (E)  客户端向资源服务器请求受保护的资源,并出示访问令牌
  6. (F)  资源服务器校验访问令牌,如果令牌有效,则提供服务

 

联想一下微信公众平台开发,在微信公众平台开发过程中当我们访问某个页面,页面可能弹出一个提示框应用需要获取我们的个人信息问是否允许,点确认其实就是授权第三方应用获取我们在微信公众平台的个人信息。这里微信网页授权就是使用的OAuth2.0。

 

 微信网页授权实例

[微信公众平台|开发文档] http://mp.weixin.qq.com/wiki/home/

实现步骤:

1 第一步:用户同意授权,获取code

2 第二步:通过code换取网页授权access_token

3 第三步:拉取用户信息(需scope为 snsapi_userinfo)

 

第一步:用户同意授权,获取code

 拼接如下地址,替换其中的参数, 在微信下打开

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。

获取code代码示例

/**
     * @explain
     * 获取code,用于获取openid和access_token
     * @remark
     * code只能使用一次,当获取到之后code失效,再次获取需要重新进入
     * 不会弹出授权页面,适用于关注公众号后自定义菜单跳转等,如果不关注,那么只能获取openid
     **/
    public function getCode()
    {
        if (isset($_GET["code"])) {
            return $_GET["code"];
        } else {
            $str = "location: https://open.weixin.qq.com/connect/oauth2/authorize?appid=" . $this->appid . "&redirect_uri=" . $this->index_url . "&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect";
            header($str);
            exit;
        }
    }

 

第二步:通过code换取网页授权access_token

替换链接中的参数,在服务器端通过curl请求以下地址

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

返回数据如下

{
    "access_token":"ACCESS_TOKEN",
    "expires_in":7200,
    "refresh_token":"REFRESH_TOKEN",
    "openid":"OPENID",
    "scope":"SCOPE" 
 }

  代码示例:

/**
     * @explain
     * 用于获取access_token,返回的<span style="font-family: Arial, Helvetica, sans-serif;">$access_token_array中也包含有用户的openid信息。</span>
     **/
    public function getOpenId()
    {
        $access_token_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" . $this->appid . "&secret=" . $this->appsecret . "&code=" . $this->code . "&grant_type=authorization_code";
        $access_token_json = $this->https_request($access_token_url);
        $access_token_array = json_decode($access_token_json, TRUE);
        return $access_token_array;
    }

  

第三步:拉取用户信息(需scope为 snsapi_userinfo)

http:GET(请使用https协议) https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

返回数据如下:

{   
    "openid":" OPENID",
    " nickname": NICKNAME,
    "sex":"1",
    "province":"PROVINCE"
    "city":"CITY",
    "country":"COUNTRY",
    "headimgurl":       "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
    "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
    "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}

  代码示例

/**
     * @explain
     * 获取到用户的openid之后可以判断用户是否有数据,可以直接跳过获取access_token,也可以继续获取access_token
     **/
    public function getUserInfo()
    {
        
        $userinfo_url = "https://api.weixin.qq.com/sns/userinfo?access_token=".$this->access_token[\'access_token\'] ."&openid=" . $this->access_token[\'openid\']."&lang=zh_CN";
        $userinfo_json = $this->https_request($userinfo_url);
        $userinfo_array = json_decode($userinfo_json, TRUE);
        return $userinfo_array;
    }