之前翻译过一篇
OAuth认证协议原理分析及使用方法
,虽然 OAuth2还没有正式发布,但是国内外的OAuth2的采用情况几乎要完全替代掉OAuth1.1了。像淘宝、腾讯、人人网、百度开放平台就已经采用Oauth2,新浪微博也发来邮件说是要很快上马OAuth2,彻底替换掉OAuth1.1。目前OAuth2到了
v20草稿阶段
,最新的版本是 2011年7月25号发布的,协议变化还是很快的,所以看到国内的一些已经实现的实例,再比照官方的 oauth2,会有些出入的。
1
2
3
|
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
|
,其中response_type 值固定为 code,client_id就是客户端申请开发者的时候取得的 appkey,state是一个可选参数,可以用于保存客户端在引导用户转向前的一些状态,当回到 redirect_uri的时候会原封不动的传回来,redirect_uri是当用户确认授权应用访问的时候跳转回来的地址。
2,用户同意授权后跳转回来的的地址如:
1
2
3
|
HTTP/1.1 302 Found
Location: https:
//client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz
|
&state=xyz ,其中 code就是 Authorization Code,state就是上面所说的可选参数。
3,使用取得的 Authorization Code去换取Access Token:
1
2
3
4
5
6
7
|
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
|
其中 Authorization是由Client id(app key)及Client password(app secret)组合成的 http basic 验证字符串,grant_type必须为 authorization_code,code是上一步取得的 Authorization Code,redirect_uri是完成后跳转回来的网址。
如果Client不能发送 Authorization信息,则可以使用下面的方式,/token这个地址必须是 https连接的,不然就有泄露 client secret的可能性:
1
2
3
4
5
6
|
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
&client_id=s6BhdRkqt3&client_secret=7Fjfp0ZBr1KtDRbnfVdmIw
|
成功的话返回的信息为:
1
2
3
4
5
6
7
8
9
10
11
12
|
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,
"refresh_token"
:
"tGzv3JOkF0XG5Qx2TlKWIA"
,
"example_parameter"
:
"example_value"
}
|
1
2
3
|
GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
|
这里的 response_type为 token,client_id为appkey。可以看到这里取Access token的过程中并没有像 第一种方式那样传入 client_secret。因为如果你传入 client_secret,其实就是相当于告诉用户,你应用的app secret了。
二、在成功授权后,跳转回到 redirect_uri所定义的网址
1
2
3
|
HTTP/1.1 302 Found
Location: http:
//example.com/rd#access_token=2YotnFZFEjr1zCsicMWpAA
&state=xyz&token_type=example&expires_in=3600
|
,这样应用就可以通过取地址中的 fragment部分来取得 access token。
1
2
3
4
5
6
|
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
grant_type=password&username=johndoe&password=A3ddj3w
|
这里的 Authorization是 client_id为username,client_secret为password的http basic验证码。grant_type必须为 password,username为用户名,password为用户密码。
取得的结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
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,
"refresh_token"
:
"tGzv3JOkF0XG5Qx2TlKWIA"
,
"example_parameter"
:
"example_value"
}
|
Q:为何要这种这么不安全的方式?
A:取代原来原始的 username,password的授权方式,而且不需要 client保存用户的密码,client只要保存access token就可以。主要用于客户端程序。
1
2
3
4
5
6
|
POST /token HTTP/1.1
Host: server.example.com
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,
返回如下:
1
2
3
4
5
6
7
8
9
10
11
|
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极可能被其它方获取。比如
1
2
3
|
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: Bearer 7Fjfp0ZBr1KtDRbnfVdmIw
|
bearer是指 token类型
,后面的字符串就是access token。还有一种
mac类型的 token(目前v20版本的草稿里还没有文档)
,如:
1
2
3
4
5
|
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。如:
1
2
3
4
5
6
7
8
|
{
"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的时候,如下:
1
2
|
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信息,所以对于任何获取
1
2
|
"session_key"
:
"9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A="
,
"session_secret"
:
"27e1be4fdcaa83d7f61c489994ff6ed6"
,
|
的一方都可以调用到API。降低系统耦合度。