OAuth2.0是OAuth1.0的延续版本,但是不向后兼任,本文只讨论2.0版本.
OAuth是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源,而无需将用户名和密码提供给第三方应用.
其实这种场景在现在已经十分普遍,比如很多论坛,都会开放支持使用QQ登录,试想如果没有OAuth,你在遇见这些感兴趣的论坛想进行评论发帖时,要么注册一个论坛账号,要么把你的QQ账号密码直接告诉论坛,很显然前者很繁琐,后者不安全,而OAuth正是帮你解决这些问题.
OAuth引入了授权层来区分用户和第三方客户端,不同于用户直接使用个人密码凭证,客户端使用令牌来访问用户的私密资源,该令牌包含诸如:范围,有效期以及其他的访问相关属性.
OAuth定义了四种角色:
- resource owner(资源所有者):一个允许访问受保护资源的实体,如果这是一个人,也叫做终端用户.
- resource server(资源服务器):这台服务器承载着受保护的资源,它有能力接收并响应哪些对受保护资源发起的请求.
- client(客户端):通过资源所有者和他的授权发起访问受保护资源的应用
- authorization server(授权服务器):在成功验证资源所有者并获得授权后,发送令牌给客户端
OAuth协议流程:
(A)客户端请求资源所有者授权(授权请求可以直接通过资源所有者,更好的方式是使用授权服务器作为中介).
(B)若资源所有者同意授权,客户端会接收到授权许可.
(C)客户端使用上一步获得的授权许可,向授权服务器申请令牌.
(D)授权服务器对客户端的授权许可进行验证,确认无误后发放令牌.
(E)客户端使用令牌,向资源服务器申请获取资源.
(F)资源服务器对令牌进行验证,确认无误后同意向客户端开放资源.
在上述六个步骤中,第二步客户端获得授权许可是关键步骤,OAuth定义了四中授权方式:
Authorization Code(授权码模式):
授权码模式使用授权服务器作为客户端和资源所有者的中介,不直接向资源所有者请求授权,而是通过客户端引导资源所有者到授权服务器(通过用户代理:如浏览器),授权服务器会验证资源所有者,验证通过获得授权后,会重新引导资源所有者返回到客户端页面,此时,客户端就可以得到授权码.因为资源所有者仅在授权服务器进行了身份验证,所以他的凭证不会被客户端所获取.授权码模式提供了很好的安全保障,比如可以验证客户端身份,直接传输令牌到客户端而不需要经过用户代理从而被暴露给其他人的可能性.
(A) 客户端导向资源所有者的用户代理到授权服务器,在此过程中会同时传递客户端标识,请求范围,本地状态以及一个用于授权服务器回跳的URI.
- response_type:表示授权类型,必选项,此处的值固定为"code"
- client_id:表示客户端的ID,必选项
- redirect_uri:表示重定向URI,可选项
- scope:表示申请的权限范围,可选项
- state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值.
(B) 授权服务器验证资源所有者并决定是否同意客户端的授权申请.
(C) 假设资源所有者同意访问,授权服务器就会重定向用户代理到客户端之前指定的回跳地址,并附上一个授权码.
- code:表示授权码,必选项.该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝.该码与客户端ID和重定向URI,是一一对应关系.
- state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数.
(D) 客户端附上之前获得的授权码向授权服务器申请令牌,这个请求过程授权服务器将会验证客户端身份.
- grant_type:表示使用的授权模式,必选项,此处的值固定为"authorization_code".
- code:表示上一步获得的授权码,必选项.
- redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致.
- client_id:表示客户端ID,必选项.
(E) 授权服务器验证客户端身份,确认授权码,并确保收到的回跳地址和在C步骤中得一致.如果全都验证通过,授权服务器返回访问令牌和更新令牌给客户端.
- access_token:表示访问令牌,必选项.
- token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型.
- expires_in:表示过期时间,单位为秒.如果省略该参数,必须其他方式设置过期时间.
- refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项.
- scope:表示权限范围,如果与客户端申请的范围一致,此项可省略.
Implicit(隐式授权模式):
隐式授权是针对基于浏览器实现的使用脚本语言的客户端的简化版授权码流程,它会直接给客户端分配访问令牌而不是授权码.服务器也不回验证客户端身份而是通过验证回跳URL来验证客户端ID,然后把令牌传递给客户端.隐式授权模式提高了响应能力和效率,因为它减少了获得令牌的请求次数.然而易用性上升的同时也会在安全性上有所下降,我们需要权衡利弊.
(A) 客户端导向资源所有者的用户代理到授权服务器,在此过程中会同时传递客户端标识,请求范围,本地状态以及一个用于授权服务器回跳的URI.
- response_type:表示授权类型,此处的值固定为"token",必选项。
- client_id:表示客户端的ID,必选项。
- redirect_uri:表示重定向的URI,可选项。
- scope:表示权限范围,可选项。
- state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
(B) 授权服务器验证资源所有者并决定是否同意客户端的授权申请.
(C) 假设资源所有者同意访问,授权服务器就会重定向用户代理到客户端之前指定的回跳地址,并附上令牌片段.
- access_token:表示访问令牌,必选项。
- token_type:表示令牌类型,该值大小写不敏感,必选项。
- expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
- scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
- state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
(D) 用户代理请求客户端页面资源(并本地维持片段信息).
(E) 返回一个包含脚本的页面,它可以提取片段中的令牌信息.
(F) 用户代理执行本地脚本进而提取令牌.
(G) 用户代理传递令牌给客户端.
Resource Owner Password Credentials(密码模式):
密码模式适用于资源所有者信任高度信任客户端的场景,例如设备操作系统或者一些特权应用.授权服务器应该只有再无法执行其他模式的情况下才采用该种模式.
(A) 资源所有者提供自己的用户名和密码给客户端.
(B) 客户端使用获得的凭证向授权服务器申请令牌.
(C) 授权服务器验证客户端凭证,如果通过,返回令牌.
- access_token:表示访问令牌,必选项。
- token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
- expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
- refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
- scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
Client Credentials(客户端模式):
客户端以自己的名义,而不是以资源所有者的名义,向授权服务器进行认证.在这种模式中,用户直接向客户端注册,客户端以自己的名义要求授权服务器提供服务,其实不存在授权问题.
(A) 客户端向授权服务器申请令牌.
(B) 资源服务器验证客户端,通过后返回令牌.
更新令牌:
当访问令牌失效过期时,我们需要使用更新令牌来重新获得访问令牌.不同于访问令牌,更新令牌永远都不会被用于资源服务器.
(A) 客户端向授权服务器请求令牌.
(B) 授权服务器验证客户端身份并验证授权许可,如果通过,返回访问令牌和更新令牌.
(C) 客户端使用访问令牌向资源服务器申请受保护资源.
(D) 资源服务器验证访问令牌,如果有效,提供资源服务.
(E) 重复C,D步骤直至访问令牌失效.
(F) 因为访问令牌失效,资源服务器返回令牌失效错误.
(G) 客户端使用更新令牌向授权服务器申请新的访问令牌.
(H) 授权服务器验证客户端身份和更新令牌,如果通过,返回一个新的访问令牌.
参考资料地址:
https://tools.ietf.org/html/rfc6749
http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
https://www.cnblogs.com/flashsun/p/7424071.html