原文:
http://www.cnblogs.com/Irving/p/4134629.html
- web:http://oauth.net/2/
- rfc: http://tools.ietf.org/html/rfc6749
- doc:http://oauth.net/documentation/
- code:http://oauth.net/code/
什么是OAuth2.0
OAuth2.0是一个开放协议,允许用户让第三方应用以安全且标准的方式获取该用户在某一网站、移动或桌面应用上存储的私密的资源(如用户个人信息、照片、视频、联系人列表),而无需将用户名和密码提供给第三方应用。
OAuth 2.0是OAuth协议的下一版本,但不向后兼容OAuth 1.0。 OAuth 2.0关注客户端开发者的简易性,同时为Web应用,桌面应用和手机,和起居室设备提供专门的认证流程。
OAuth 允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的网站(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要分享他们的访问许可或他们数据的所有内容。
OAuth2授权流程
在讲述OAuth2.0之前先得了解基本授权的基本术语:
资源拥有者(resource owner):能授权访问受保护资源的一个实体,如新浪微博用户 web3d;
资源服务器(resource server):存储受保护资源,客户端通过access token请求资源,资源服务器响应受保护资源给客户端;存储着用户irving的微博等信息。
授权服务器(authorization server):成功验证资源拥有者并获取授权之后,授权服务器颁发授权令牌(Access Token)给客户端。
客户端(client):如新浪微博第三方应用,也可以是它自己的官方应用;其本身不存储资源,而是资源拥有者授权通过后,使用它的授权(授权令牌)访问受保护资源,然后客户端把相应的数据展示出来。“客户端”术语不代表任何特定实现(如应用运行在一台服务器、桌面、手机或其他设备)。
+--------+ +---------------+
| |--(A)- Authorization Request ->| Resource |
| | | Owner |
| || Authorization |
| Client | | Server |
| || Resource |
| | | Server |
| |
OAuth2授权模式
客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式。
- 授权码模式(authorization code)
- 简化模式(implicit)
- 密码模式(resource owner password credentials)
- 客户端模式(client credentials)
因为一般授权码的使用的比较多,客户端可能会使用简化模式或客户端模式,我这里只简述授权码模式,授权码流程
+----------+
| Resource |
| Owner |
| |
+----------+
^
|
(B)
+----|-----+ Client Identifier +---------------+
| -+----(A)-- & Redirection URI ---->| |
| User- | | Authorization |
| Agent -+----(B)-- User authenticates --->| Server |
| | | |
| -+----(C)-- Authorization Code ------(D)-- Authorization Code ---------' |
| Client | & Redirection URI |
| | |
| |
- (A)用户授权访问认证服务器
- (B)用户选择是否给予客户端授权
- (C)如果给予授权,认证服务器(authorization service)将重定向(http状态码302)到A流程中给予的URL(redirect_uri),同时附上一个授权码(code)
- (D)客户端收到授权码(code),向认证服务器(authorization service)申请令牌(发送post请求)。这个过程是在客户端的后台请求上完成的,对用户不可见
- (E)认证服务器检查授权码(code)和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)以及失效时间(expires_in)
如新浪的授权流程图:
1、客户端从资源拥有者给予授权
比如我现在使用新浪微博的账户授权登录知乎。
GET /oauth/auth/sina?next=/oauth/account_callback HTTP/1.1
Host: www.zhihu.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://www.zhihu.com/
请求包含以下参数:
- response_type:表示授权类型,必选项,此处的值固定为"code"
- client_id:表示客户端的ID,必选项
- redirect_uri:表示重定向URI,可选项
- scope:表示申请的权限范围如 user,order,可选项
- state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
一般开发一个基于新浪微博app的第三方应用,需要申请appkey和appsecret分别对应OAuth2.0中的client_id与client_secret,可能一些服务端会扩展一些其他的名称,腾讯就是这个干的。
2、用户同意给予客户端授权
分两种情况,如果是没有微博登录成功的会话,就让用户登录,如上图如果之前我已经有了登录成功的会话了,这个时候就让用户确认同意授权(知乎好流氓,直接略了这一步,但是流程还是一样的),我用其他网站的联合登录截了个图如下。
CONNECT api.weibo.com:443 HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0
Connection: keep-alive
Connection: keep-alive
Host: api.weibo.com:443
GET /oauth/auth/request_sina_token?next=%2Foauth%2Faccount_callback&state=78db9a8b58b2dab6970d4520907ad629&code=879c3a9aabdf5dfe69b92092204fe480 HTTP/1.1
Host: www.zhihu.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://www.zhihu.com/
Connection: keep-alive
授权成功返回如下参数:
- code:表示授权码,必选项。通常授权码只能使用该码一次,并且会设置有效时间。
- state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
3、客户端使用授权码向认证服务器申请令牌。
这个过程发生在客户端后台,用户不可见,这也是授权码模式的特性,更安全。大致接口地址类似(服务端会验证client_id、client_secret、auth code的正确性或更新令牌 refresh_token):
http://localhost:8080/oauth2/access_token?client_id={AppKey}&client_secret={AppSecret}&grant_type=authorization_code&redirect_uri={YourSiteUrl}&code={code}
向认证服务器申请令牌包含以下参数:
- grant_type:表示使用的授权模式,必选项,此处的值固定为"authorization_code"。
- code:表示上一步获得的授权码,必选项。
- redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
- client_id:表示客户端ID,必选项
- client_secret:表示客户端密钥,必选项。
4、如果授权码验证成功,则下生成一个令牌。
这个过程发生在服务端后台,服务端会验证client_id、client_secret、auth code的合法性,成功则生成一个令牌。
认证服务器返回,包含以下参数:
- access_token:表示访问令牌,必选项。
- token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
- expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
- refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
- scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
5、客户端使用访问令牌向资源服务器请求受保护资源。
客户端实现,请求用户保护的资源。
知乎成功后返回:
- GET /oauth/account_callback?callbacktype=sina HTTP/1.1
- Host: www.zhihu.com
- User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0
- Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
- Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
- Accept-Encoding: gzip, deflate
- Referer: http://www.zhihu.com/
- Connection: keep-alive
6、资源服务器验证访问令牌的有效性则开放保护的资源。
服务端实现,验证令牌合法性后则开放用户授权的保护资源,很多时候,用户的资源是与权限对应的。令牌可能只包含了用户特定的授权凭据,准确的说,令牌对应用户授权时所赋予的一系列权限的集合。所以在这一步,除了校验令牌的合法性之外,服务端还需对该令牌是否拥有足够的权限执行被保护操作进行验证。