一、什么是OAuth2
OAuth 2.0 是一个基于令牌 Token 的授权协议,通过它我们可以在不暴露账户和密码的情况下授予客户应用有限的数据访问权限。它解藕了认证和授权,同时它是事实上的安全框架,它能支持服务与服务,App、单页面应用与后端服务等很多应用场景。
不难理解,OAuth的作用就是让"客户端"安全可控地获取"用户"的授权。
OAuth2是用来允许用户授权第三方应用访问他在另一个服务器上的资源的一种协议,它不是用来做单点登录的,但可以利用它来实现单点登录。
二、名词定义
·Third-party application:第三方应用程序,又称"客户端"(client)。
·Resource Owner:资源所有者(eg: user)。
·Authorization server:认证服务器,即授权服务器。
·Resource server:资源服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。
HTTP service:HTTP服务提供商。
User Agent:用户代理(eg:浏览器)。
三、运行流程
(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源(eg:资源指用户信息等)。
(F)资源服务器确认令牌无误,同意向客户端开放资源。
四、客户端的授权模式
客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式。
◆授权码模式(authorization code)
◆简化模式(implicit)
◆密码模式(resource owner password credentials)
◆客户端模式(client credentials)
1、授权码模式
授权码式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与"服务提供商"的认证服务器进行互动。
它的步骤如下:
(A)用户访问客户端,后者将前者导向认证服务器。
https://***?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos&state=1234zyx
· code: 代表服务器希望收到授权码;
· client_id: 注册应用时颁发的ID;
· redirect_uri: 指明当用户授权完成之后返回的地址;
· scope: 一个或多个值,用来指明希望获得用户账户哪部分权限;
· state:由应用生成的一个随机字符串,会在稍后的过程中去验证。
通过以上的链接,用户将会看到如下的界面
(B)用户选择是否给予客户端授权。
(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码(code)。
https://***?code=AUTH_CODE_HERE&state=1234zyx
· code: 服务器返回的授权码;
· state: 返回请求授权码过程中发送的state;
当应用接收到这个请求时,要首先验证state是否就是应用刚才发送的值。在发送state之后,可以把state保存到Session以便于后续的比较。这样做的目的是防止应用接受任意伪造的授权码。
(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
https://***/access_token?grant_type=authorization_code&code=AUTH_CODE_HERE&redirect_uri=REDIRECT_URI&client_id=CLIENT_ID&client_secret=CLIENT_SECRET
· grant_type=authorization_code - 代表授权模式为验证码;
· code=AUTH_CODE_HERE - 验证码;
· redirect_uri=REDIRECT_URI - 重定向URI;
· **client_id=CLIENT_ID **- 注册应用时颁发的ID;
· client_secret=CLIENT_SECRET - 客户端密钥,因为当前请求时服务器之间传输的,并没有暴露给用户。
(E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
{
"access_token":"RsT5OjbzRn430zqMLgV3Ia",
"refresh_token":"josg5KNS52ndajha5afdifd",
"expires_in":3600
}
2、隐式授权模式/简化模式
和授权码模式类似,只不过少了获取code的步骤,是直接获取令牌token的,适用于公开的浏览器单页应用,令牌直接从授权服务器返回,不支持刷新令牌,且没有code安全保证,令牌容易因为被拦截窃听而泄露。
它的步骤如下:
(A)客户端将用户导向认证服务器。
https://***/authorize?response_type=token&client_id=s6BhdRkqt3&state=xyzredirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1Host: server.example.com
· response_type:表示授权类型,此处的值固定为"token",必选项。
· client_id:表示客户端的ID,必选项。
· redirect_uri:表示重定向的URI,可选项。
· scope:表示权限范围,可选项。
· state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
(B)用户决定是否给于客户端授权。
(C)假设用户给予授权,认证服务器将AccessToken以Hash的形式存放在重定向uri的链接中发送给浏览器。
http://***/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600
· access_token:表示访问令牌,必选项。
· token_type:表示令牌类型,该值大小写不敏感,必选项。
· expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
· scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
· state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
(D)浏览器向资源服务器发出请求,即访问重定向URI。
(E)资源服务器返回一个网页,其中包含的代码可以获取Hash值中的令牌。
(F)浏览器执行上一步获得的脚本,提取出令牌。
(G)浏览器将令牌发给客户端。
3、密码模式
用户直接给第三方应用提供在提供服务端账号密码,获取服务端的 access_token 。
在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。
它的步骤如下:
(A)用户向客户端提供用户名和密码。
(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。
客户端发出的HTTP请求,包含以下参数:
· grant_type:表示授权类型,此处的值固定为"password",必选项。
· username:表示用户名,必选项。
· password:表示用户的密码,必选项。
· scope:表示权限范围,可选项。
(C)认证服务器确认无误后,向客户端提供访问令牌。
4、客户端模式
指客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求"服务提供商"提供服务,其实不存在授权问题。
这种授权方式常用于第三方应用想要更改自身在服务提供方注册的应用信息,比如更改应用描述或回调链接地址。
它的步骤如下:
(A)客户端向认证服务器进行身份认证,并要求一个访问令牌。
客户端发出的HTTP请求,包含以下参数:
· granttype:表示授权类型,此处的值固定为"clientcredentials",必选项。
· scope:表示权限范围,可选项。
认证服务器必须以某种方式,验证客户端身份。
(B)认证服务器确认无误后,向客户端提供访问令牌。
五、四种授权模式特点
授权码模式(authorization code)
这种模式算是正宗的oauth2的授权模式
设计了auth code,通过这个code再获取token
支持refresh token
简化模式(implicit)
这种模式比授权码模式少了code环节,回调url直接携带token
这种模式的使用场景是基于浏览器的应用
这种模式基于安全性考虑,建议把token时效设置短一些
不支持refresh token
密码模式(resource owner password credentials)
这种模式是最不推荐的,因为client可能存了用户密码
这种模式主要用来做遗留项目升级为oauth2的适配方案
当然如果client是自家的应用,也是可以
支持refresh token
客户端模式(client credentials)
这种模式直接根据client的id和密钥即可获取token,无需用户参与
这种模式比较合适消费api的后端服务,比如拉取一组用户信息等
不支持refresh token,主要是没有必要
注:refresh token的初衷主要是为了用户体验不想用户重复输入账号密码来换取新token,因而设计了refresh token用于换取新token。客户端模式由于没有用户参与,而且也不需要用户账号密码,仅仅根据自己的id和密钥就可以换取新token,因而没必要refresh token
小结
授权码模式(authorization code)(正宗方式)(支持refresh token)
密码模式(resource owner password credentials)(为遗留系统设计)(支持refresh token)
简化模式(implicit)(为web浏览器应用设计)(不支持refresh token)
客户端模式(client credentials)(为后台api服务消费者设计)(不支持refresh token)