Spring Security OAuth几种模式

OAuth的几种模式

​ OAuth在"客户端"与"服务提供商"之间,设置了一个授权层(authorization layer)。

​ “客户端"不能直接登录"服务提供商”,只能登录授权层,以此将用户与客户端区分开来。

​ "客户端"登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围和有效期,"客户端"登录授权层以后,"服务提供商"根据令牌的权限范围和有效期,向"客户端"开放用户储存的资料。

OAuth 2.0的运行流程如下图,摘自RFC 6749:

在这里插入图片描述

(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向授权服务器申请令牌。
(D)授权服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。

令牌(token)与密码(password)的作用是一样的,都可以进入系统,但是有三点差异。
(1)令牌是短期的,到期会自动失效,用户自己无法修改。密码一般长期有效,用户不修改,就不会发生变化。
(2)令牌可以被数据所有者撤销,会立即失效。密码一般不允许被他人撤销。
(3)令牌有权限范围(scope)。对于网络服务来说,只读令牌就比读写令牌更安全。密码一般是完整权限。
上面这些设计,保证了令牌既可以让第三方应用获得权限,同时又随时可控,不会危及系统安全。这就是 OAuth 2.0 的
优点。

1、客户端授权模式

​ 客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。

​ OAuth 2.0 对于如何颁发令牌的细节,规定得非常详细。

​ 具体来说,一共分成四种授权类型(authorization grant),即四种颁发令牌的方式,适用于不同的互联网场景。

  • 授权码模式(authorization code)
  • 密码模式(resource owner password credentials)
  • 简化(隐式)模式(implicit)
  • 客户端模式(client credentials)

不管哪一种授权方式,第三方应用申请令牌之前,都必须先到系统备案,说明自己的身份,然后会拿到两个身份识别码:客户端 ID(client ID)和客户端密钥(client secret)。这是为了防止令牌被滥用,没有备案过的第三方应用,是不会拿到令牌的

在这里插入图片描述

授权码模式

授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。

这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。

适用场景:目前市面上主流的第三方验证都是采用这种模式

在这里插入图片描述

它的步骤如下:

(A)用户访问客户端,后者将前者导向授权服务器。
(B)用户选择是否给予客户端授权。
(C)假设用户给予授权,授权服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授
权码。
(D)客户端收到授权码,附上早先的"重定向URI",向授权服务器申请令牌。这一步是在客户端的后台的服务器上完
成的,对用户不可见。
(E)授权服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌
(refresh token)。

  • A网站提供一个链接,用户点击后就会跳转到 B 网站,授权用户数据给 A 网站使用。下面就是 A 网站跳转B 网站的一个示意链接。

    1 > https://b.com/oauth/authorize?
    2 > response_type=code& #要求返回授权码(code)
    3 > client_id=CLIENT_ID& #让 B 知道是谁在请求
    4 > redirect_uri=CALLBACK_URL& #B 接受或拒绝请求后的跳转网址
    5 > scope=read # 要求的授权范围(这里是只读)
    
    • 客户端申请授权的URI,包含以下参数:
      • response_type:表示授权类型,必选项,此处的值固定为"code"
      • client_id:表示客户端的ID,必选项
      • redirect_uri:表示重定向URI,可选项
      • scope:表示申请的权限范围,可选项
      • state:表示客户端的当前状态,可以指定任意值,授权服务器会原封不动地返回这个值。
  • 用户跳转后,B 网站会要求用户登录,然后询问是否同意给予 A 网站授权。用户表示同意,这时 B 网站就会跳回redirect_uri参数指定的网址。跳转时,会传回一个授权码,就像下面这样。

    1 > https://a.com/callback?code=AUTHORIZATION_CODE #code参数就是授权码
    
  • A 网站拿到授权码以后,就可以在后端,向 B 网站请求令牌。 用户不可见,服务端行为

    1 > https://b.com/oauth/token?
    2 > client_id=CLIENT_ID&
    3 > client_secret=CLIENT_SECRET& # client_id和client_secret用来让 B 确认 A 的身份,client_secret参数是保密
    的,因此只能在后端发请求
    4 > grant_type=authorization_code& # 采用的授权方式是授权码
    5 > code=AUTHORIZATION_CODE& # 上一步拿到的授权码
    6 > redirect_uri=CALLBACK_URL # 令牌颁发后的回调网址
    
  • B 网站收到请求以后,就会颁发令牌。具体做法是向redirect_uri指定的网址,发送一段 JSON 数据。

    1 > {
    2 > "access_token":"ACCESS_TOKEN", # 令牌
    3 > "token_type":"bearer",
    4 > "expires_in":2592000,
    5 > "refresh_token":"REFRESH_TOKEN",
    6 > "scope":"read",
    7 > "uid":100101,
    8 > "info":{...}
    9 > }
    
    简化(隐式)模式

    ​ 有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端。RFC 6749就规定了第二种方式,允许直接向前端颁发令牌,这种方式没有授权码这个中间步骤,所以称为(授权码)“隐藏式”(implicit)

    ​ 简化模式不通过第三方应用程序的服务器,直接在浏览器中向授权服务器申请令牌,跳过了"授权码"这个步骤,所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。

    ​ 这种方式把令牌直接传给前端,是很不安全的。因此,只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期间(session)有效,浏览器关掉,令牌就失效了。

    在这里插入图片描述

    它的步骤如下:

    (A)客户端将用户导向授权服务器。
    (B)用户决定是否给于客户端授权。
    (C)假设用户给予授权,授权服务器将用户导向客户端指定的"重定向URI",并在URI的Hash部分包含了访问令牌。
    (D)浏览器向资源服务器发出请求,其中不包括上一步收到的Hash值。
    (E)资源服务器返回一个网页,其中包含的代码可以获取Hash值中的令牌。
    (F)浏览器执行上一步获得的脚本,提取出令牌。
    (G)浏览器将令牌发给客户端。

  • A 网站提供一个链接,要求用户跳转到 B 网站,授权用户数据给 A 网站使用。

    1 > https://b.com/oauth/authorize?
    2 > response_type=token& # response_type参数为token,表示要求直接返回令牌
    3 > client_id=CLIENT_ID&
    4 > redirect_uri=CALLBACK_URL&
    5 > scope=read
    6 >
    
  • 用户跳转到 B 网站,登录后同意给予 A 网站授权。这时,B 网站就会跳回redirect_uri参数指定的跳转网址,并且把令牌作为 URL 参数,传给 A 网站。

    1 > https://a.com/callback#token=ACCESS_TOKEN #token参数就是令牌,A 网站直接在前端拿到令牌。
    2 >
    
密码模式

​ 如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为"密码式"(password)。

​ 在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而授权服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。
适用场景:自家公司搭建的授权服务器

在这里插入图片描述

它的步骤如下:

(A)用户向客户端提供用户名和密码。
(B)客户端将用户名和密码发给授权服务器,向后者请求令牌。
(C)授权服务器确认无误后,向客户端提供访问令牌。

  • A 网站要求用户提供 B 网站的用户名和密码,拿到以后,A 就直接向 B 请求令牌。整个过程中,客户端不得保存用户的密码。

    1 > https://oauth.b.com/token?
    2 > grant_type=password& # 授权方式是"密码式"
    3 > username=USERNAME&
    4 > password=PASSWORD&
    5 > client_id=CLIENT_ID
    6 >
    
  • B 网站验证身份通过后,直接给出令牌。注意,这时不需要跳转,而是把令牌放在 JSON 数据里面,作为HTTP 回应,A 因此拿到令牌。在这里插入图片描述

客户端模式

​ 客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行授权。
适用于没有前端的命令行应用,即在命令行下请求令牌。一般用来提供给我们完全信任的服务器端服务。

在这里插入图片描述

它的步骤如下:

(A)客户端向授权服务器进行身份认证,并要求一个访问令牌。
(B)授权服务器确认无误后,向客户端提供访问令牌。

  • A 应用在命令行向 B 发出请求。
1 > https://oauth.b.com/token?
2 > grant_type=client_credentials&
3 > client_id=CLIENT_ID&
4 > client_secret=CLIENT_SECRET
  • B 网站验证通过以后,直接返回令牌。在这里插入图片描述

令牌的使用

A 网站拿到令牌以后,就可以向 B 网站的 API 请求数据了。

此时,每个发到 API 的请求,都必须带有令牌。具体做法是在请求的头信息,加上一个Authorization字段,令牌就放在这个字段里面。

1 > curl ‐H "Authorization: Bearer ACCESS_TOKEN" \
2 > "https://api.b.com"
3 >

也可以通过添加请求参数access_token请求数据。在这里插入图片描述

更新令牌

令牌的有效期到了,如果让用户重新走一遍上面的流程,再申请一个新的令牌,很可能体验不好,而且也没有必要。OAuth 2.0 允许用户自动更新令牌。在这里插入图片描述

具体方法是,B 网站颁发令牌的时候,一次性颁发两个令牌,一个用于获取数据,另一个用于获取新的令牌(refresh token 字段)。令牌到期前,用户使用 refresh token 发一个请求,去更新令牌。

1 > https://b.com/oauth/token?
2 > grant_type=refresh_token& # grant_type参数为refresh_token表示要求更新令牌
3 > client_id=CLIENT_ID&
4 > client_secret=CLIENT_SECRET&
5 > refresh_token=REFRESH_TOKEN # 用于更新令牌的令牌
6 >

在这里插入图片描述

  • 18
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值