OAuth 2.0定义了四种授权方式。
1.授权码模式(authorization code)
2.简化模式(implicit)
3.密码模式(resource owner password credentials)
4.客户端模式(client credentials)
ClientCredentials客户端模式:
Client使用自己的 client证书(如 client_id及client_secret组成的 http basic验证码)来获取 access token,只能用于信任的client
场景:
认证服务器不提供像用户数据这样的重要资源,仅仅是有限的只读资源或者一些开放的API。例如使用了第三方的静态文件服务,如Google Storage或Amazon S3。这样,你的应用需要通过外部API调用并以应用本身而不是单个用户的身份来读取或修改这些资源。这样的场景就很适合使用客户端证书授权。
应用程序需要向认证服务器申请访问令牌,而该请求则需要客户端证书进行认证。
假设现在我们正在折腾环信IM,其认证URL为:
https://a1.easemob.com/pair/pair/token
这里需要使用POST请求并附带以下参数:
grant_type
这里为“client_credentials”
client_id
应用注册时获得的client id
client_secret
应用注册时获得的client secret
以下是一个通过命令行HTTP客户端curl发起的请求示例:
curl -d "grant_type=client_credentials\
&client_id=2016273333331117128396\
&client_secret=904b98aaaaaaac1c92381d2" \
https://a1.easemob.com/pair/pair/token
POST /token HTTP/1.1
Host: a1.easemob.com/pair/pair/token
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
grant_type=client_credentials
其中Authorization是client_id及client_secret组成的http_basic验证串。grant_type必须为client_credentials!
如果认证成功,服务器将会返回令牌access_token:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"example_parameter":"example_value"
}
标准的 oauth2中,使用 access token来向资源服务器发出请求,取得资源。这里的资源服务器需要使用 https协议,否则access token极可能被其它方获取。比如环信注册用户
GET /resource/1 HTTP/1.1
Host: a1.easemob.com/pair/pair/users
Authorization: Bearer 7Fjfp0ZBr1KtDRbnfVdmIw
bearer是指 token类型,后面的字符串就是access token。
还有一种 mac类型的 token(目前v20版本的草稿里还没有文档),如:
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: MAC id="h480djs93hd8",
nonce="274312:dj83hs9s",
mac="kDZvddkndxvhGRXZhvuDjEWhGeE="
,因为 https速度相较http慢,而且并非所有服务器或客户都支持https,所以国内一些网站采用一种http也可访问资源的方式。
淘宝开放平台的方式
:应用通过用户授权获取的AccessToken的值即等同于Sessionkey,应用凭借AccessToken调用taobao API即可。查看淘宝SDK,可以看到 其使用应用的app_secret作用密码钥来进行签名,参数里面包含了 这个Sessionkey,这样淘宝在收到这个请求的时候,根据 app_id来判断是哪个应用,根本sessionkey的值来判断是哪个用户,如果不传这个 sessionkey就用 app_id查得app_id所属的淘宝用户就行了。也就是说 sessionkey必须配合 这个 client自己的授权资料appkey appsrecet来访问资源。
百度开放平台方式、人人网方式、还有腾讯也类似:在返回 access token的同时返回 sessionKey及sessionSecret。如:
{
"access_token": "1.a6b7dbd428f731035f771b8d15063f61.86400.1292922000-2346678-124328",
"expires_in": 86400,
"refresh_token": "2.385d55f8615fdfd9edb7c4b5ebdc3e39.604800.1293440400-2346678-124328",
"scope": "basic email",
"session_key": "9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A=",
"session_secret": "27e1be4fdcaa83d7f61c489994ff6ed6",
}
在调用资源API的时候,如下:
GET /rest/2.0/passport/users/getInfo?session_key=9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A%3D×tamp=2011-06-21+17%3A18%3A09&format=json&uid=67411167&sign=d24dd357a95a2579c410b3a92495f009 HTTP/1.1
Host: api.example.com
这里参数里面的 session_key,传给服务器后,用户查询 session_secret,sign使用session_secret作为密钥来加密的。可以看到这里调用的时候没有使用 client_id或client_secret信息,所以对于任何获取
"session_key": "9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A=",
"session_secret": "27e1be4fdcaa83d7f61c489994ff6ed6",
的一方都可以调用到API。降低系统耦合度。