oauth2 spring-authorization-server 分析

1. 选型

选用 spring security 5.2.x+作为框架,在 spring security 5.2.x+ 框架中进行扩展。

Spring 曾经有旧版支持 OAuth2 的方案:Spring Security OAuth 项目,该项目已经被逐步淘汰。但网上有不少仍然是这个方案,需要充分注意他们的区别。

1.1. Spring Security 5.2.x+

1.1.1. 说明

spring security 实现 OAuth 的框架分为 spring security OAuth 项目和 spring security 5.2.x 自带的 OAuth 功能,目前 spring security OAuth 已作废,官方推荐使用 spring security 5.2.x 自带的 OAuth

1.1.2. Spring Security 5.2.x+自带 OAuth

spring security 5.2.x+ 只有资源服务器和客户端,并不包含授权服务器,官方推荐使用 spring-authorization-server,目前版本 0.2.3。

1.spring security 5.2.x+

项目地址:Spring Security

GitHub:https://github.com/spring-projects/spring-security

2.授权服务器

GitHub:https://github.com/spring-projects/spring-authorization-server

1.1.3. Spring Security OAuth 项目

spring security OAuth 项目已作废

项目地址:Spring Security OAuth

GitHub:https://github.com/spring-projects/spring-security-oauth

1.1.4. 两个项目对比分析

https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Features-Matrix

2. 核心过滤链分析

 OAuth2 方案,支持在单体应用下启用。在单体应用中使用时,该应用的角色将会同时为“授权服务器”和“资源服务器”。

单体应用下,应用会同时成为“授权服务器”和“资源服务器”。分别对应两条由 Spring Security 创建的过滤器链,用于处理授权请求和资源服务的鉴权安全。

2.1. 授权服务器 SecurityFilterChain 过滤链

配置类 AuthorizationServerSecurityAutoConfiguration

该过滤器链,会匹配下图的 URL 和 Method 的请求。

 在授权服务器的配置类生效后,将会对上图中的符合的 URL 和 Method 的请求进行拦截,也就是说,只要请求符合,都会进入这个过滤器链中被处理。

符合的请求,会经过上图中的过滤器链被处理。

过滤器链中包含比较多的过滤器,这里,比较重要的过滤器有如下介绍的。

2.1.1. OAuth2AuthorizationEndpointFilter

这个过滤器用来处理授权码认证过程中获取 code 的请求。

http://{{AuthorizationServer}}/oauth2/authorize?client_id=client&response_type=code&scope=testScope

若请求成功,返回的 302 跳转路径是:

http://localhost:8080/callback?code=EuO9WT96cMPoTB777pTuEk9TW5kZEuX-WKwbtZBJfLoEUlfGLBBmceP_qsEuOiypnkDL_wO0FyNlc9qtAxupFSx0hRBntifGjipA2zJNk897VoXd5wlib26W3PaRBkIw

这样,就能获取到授权码,进行下一步的认证了。

2.1.2. OAuth2ClientAuthenticationFilter

客户端认证过滤器,主要是对请求的客户端进行认证。无论 grant type 是授权码还是客户端认证,请求中都会包含 client id 和 client secret。此过滤器就是确认客户端的 client id 和 client secret 是否正确。

与其他过滤器不同,如果客户端认证成功,会把客户端信息转为 Authentication 对象,保存在 SecurityContext 中,然后流转到下一个过滤器。

2.1.3. OAuth2TokenEndpointFilter

处理不同 Grant Type,并真正颁发 Token(AccessToken 和 RefreshToken)的过滤器。这个过滤器是颁发的核心,并且处理的事情比较复杂,在后面从流程介绍时再进一步说明。

2.1.4. OAuth2TokenIntrospectionEndpointFilter

授权服务器会颁发 Token,同时,也负责要验证颁发出的 Token 的有效性。此过滤器被调用用于确认 Token 的有效性,Token 有效则返回属于这个 Token 的一些认证授权信息。

http://{{AuthorizationServer}}/oauth2/introspect?token={{AccessTokenUUID}}

2.1.5. OAuth2TokenRevocationEndpointFilter

负责 Token 的注销

http://{{AuthorizationServer}}/oauth2/revoke?token={{AccessTokenUUID}}

2.2. 资源服务器 SecurityFilterChain 过滤链

除授权服务器拦截的 url 外,其他任意请求都进资源服务器配置类的过滤器链。注意,任意请求的意思,也就是所有请求都要经过这里进行安全的鉴权和控制。这就是在 OAuth2 方案下进行鉴权的关键过滤器链了。

这个过滤器链,与传统(单体)应用下的过滤器链中的过滤器类(数量顺序)基本上是一致的。除了在资源服务器下新增的 BearerTokenAuthenticationFilter 过滤器。

2.2.1. BearerTokenAuthenticationFilter

在资源服务器的角度下,任何请求都需要验证该请求的有效性。请求中必须要附上 Token,那 Token 会经过此过滤器,调用认证管理器 AuthenticationManager 来对此 Token 进行校验(一般校验流程与上述授权服务器的 OAuth2TokenIntrospectionEndpointFilter 一致)。

成功后,则把校验成功的信息存储在 SecurityContext 中,然后转到下一步的过滤器进行鉴权。

3. 授权模式

对不同授权许可类型进行分析与流程的梳理、记录,并整理对此进行扩展补充的地方。

3.1. 客户端凭据许可

客户端凭据许可:grant_type=client_credentials

下面会介绍一下客户端凭据许可的使用场景。在解释的案例中,小兔软件代指一个软件应用

客户端凭据许可主要使用在访问的资源,没有明确的资源拥有者。换句话说就是,如果小兔软件访问了一个不需要用户小明授权的数据,比如获取京东 LOGO 的图片地址,这个 LOGO 信息不属于任何一个第三方用户,再比如其它类型的第三方软件来访问平台提供的省份信息,省份信息也不属于任何一个第三方用户。

此时,在授权流程中,就不再需要资源拥有者这个角色了。当然了,你也可以形象地理解为 “资源拥有者被塞进了第三方软件中” 或者 “第三方软件就是资源拥有者”。这种场景下的授权,便是客户端凭据许可,第三方软件可以直接使用注册时的 app_id 和 app_secret 来换回访问令牌 token 的值。

还是以小明使用小兔软件为例,来看下客户端凭据许可的整个授权流程,如下图所示:

这里,图示的app_idapp_secret等同于client_idclient_secret

3.1.1. 获取访问 token

3.1.1.1. 请求响应说明

请求格式

名称说明
url/oauth2/token
MethodPOST
Content-Typeapplication/x-www-form-urlencoded
Authorization格式为:Basic 。 为 base64 编码的 {client_id}:{client_secret}。

请求参数

名称说明
grant_type授权许可类型。 固定为 client_credentials(客户端凭据许可)
scope可选。申请的权限范围

响应

名称说明
access_token访问 token,格式为 uuid
scope申请并获得授权的 scope
token_typetoken 的类型。固定值 Bearer
expires_in访问 token 有效期,单位为秒

客户端凭据许可中,根据 OAuth2 规范,不会返回 refresh_token 。因此,如果 token 过期,则重新发起申请获取一次就可以了。

3.1.1.2. postman 测试结果

请求

POST /oauth2/token?grant_type=client_credentials&scope=test1 test2 HTTP/1.1
Host: localhost:8080
Authorization: Basic Y2xpZW50OjEyMzQ1Ng==

 

其中,client 客户端信息要以 Header Authorization: Basic Y2xpZW50OjEyMzQ1Ng==发送。

Y2xpZW50OjEyMzQ1Ng==是把client:123456按 Base64 编码算出来的值。

响应

{
  "access_token": "d9787169-3b82-4477-9c5f-8e8b640582ed",
  "scope": "test2 test3",
  "token_type": "Bearer",
  "expires_in": "7200"
}

3.1.1.3. 请求序列图

请求序列图详细分析如下:

客户端发起请求/oauth2/token

<1>对客户端信息进行认证

/oauth2/token接口需要客户端认证通过才能访问,OAuth2ClientAuthenticationFilter(客户端认证过滤器)拦截请求,调用OAuth2ClientAuthenticationProvider(客户端认证管理器的提供者)对传入的client_idclient_secret进行判断。登录认证成功后,设置认证成功的结果(OAuth2ClientAuthenticationToken,内含客户端信息的RegisteredClient结果)到SecurityContext中。然后跳到下一步的过滤器中。

<2>对客户端信息进行二次认证

过滤器OAuth2TokenEndpointFilter继续拦截此请求,然后在颁发 Token 之前,请求OAuth2ClientCredentialsAuthenticationProvider(客户端凭据许可认证管理器的提供者)的authenticate()方法进行第二次认证。因为第一步的OAuth2ClientAuthenticationFilter已经校验过client_secret,这里主要对 client 的授权模式是否吻合,以及 scope 的授权范围进行校验就通过了。

OAuth2TokenEndpointFilter中,调用 OAuth2XxxxAuthenticationProvider 的 authenticate() 方法进行认证是固定流程。实际会根据不同的grant_type去选择调用不同的 OAuth2XxxxAuthenticationProvider 进行认证。因此,对客户端信息进行了二次认证,第一次和第二次的认证的职责是不通的。

<3>创建访问 Token

<3.1>开始颁发 Token:增强 Token 中包含的信息

首先是要确定 Token 中包含的信息。在OAuth2ClientCredentialsAuthenticationProvider中通过 OAuth2TokenCustomizer 定制 token 相关信息(本质是定制 JwtEncodingContext 对象的 Claims 属性,相当于在一个 Map 中放进自定义的 Key 和 Value 值)。

<3.2>开始颁发 Token:修改 tokenValue 值为 uuid 格式

然后 JwtEncoder 根据定制之后的JwtEncodingContext,生成 jwtAccessToken,这里的 jwtAccessToken 可以认为只是一个以 jwt 为容器存储了 token 的不同属性信息的候选 AccessToken

<3.3>开始颁发 Token:正式颁发 OAuth2AccessToken

之后,真正颁发 AccessToken。通过 jwtAccessToken 构建 OAuth2AccessToken 对象,使用了 jwtAccessToken 的 tokenValue 值(该值是 UUID)。OAuth2AccessToken 才是真正要颁发的 AccessToken 对象。

<4>持久化 Token 及认证过程中的所有信息

为了在颁发 Token 后,能对 Token 进行验证其合法性,以及返回 Token 包含的信息,因此需要对 Token 及其相关的信息进行持久化。

结合OAuth2AccessTokenjwtAccessToken这两个对象,把它们中相关的属性抽出构建为OAuth2Authorization对象(最终的这个对象包含了客户端信息、token 信息、GrantType 信息、authorizedScopes 信息,token 中的所有 Claims 信息的集合),然后通过接口OAuth2AuthorizationService保存OAuth2Authorization对象,因为这个对象包含的信息最完整,这里保存下来后便于后续对 Token 进行校验。

<5>返回响应信息

最终,OAuth2ClientCredentialsAuthenticationProvider返回新 New 的OAuth2AccessTokenAuthenticationToken对象到OAuth2TokenEndpointFilter,这个 Filter 过滤器处理转换为返回给前端的响应OAuth2AccessTokenResponse

OAuth2AccessTokenResponse 对象

3.1.2. 校验 token,访问需要 API 权限的接口

第三方客户端,请求访问资源时,需要携带 token 来进行访问。

这里以访问接口 /api/users/{{user_id}} 为例说明。

3.1.2.1. postman 测试

访问需要权限的接口

将获取的 access_token 复制到请求头 Authorization 然后值为 Bearer accessToken 值。如下图所示。

3.1.2.2. token校验方式

3.1.2.3. 通过HTTP校验Token请求序列图

这里的请求序列图,主要描述在过滤器链中的过滤器如何对 token 的有效性进行判断,不会涉及对 /api/users/{{user_id}} 这个请求具体的业务处理逻辑进行描述。

请求权限保护的接口 /api/users/{{user_id}} ,接口被部署在角色为资源服务器的应用上。

资源服务器上,

<1>BearerTokenAuthenticationFilter 认证过滤器,处理 token 请求。首先,由BearerTokenResolver 类负责从 request 中读取解析出 token 值。这里。成功读取 Token 后,封装到 BearerTokenAuthenticationToken 对象中,进行下一步对 Token 的验证。

<2>OpaqueTokenAuthenticationProvider 是 Token 的认证者。

校验 Token 成功后,此处可以扩展,比如根据授权服务器校验 token 返回的信息,组装权限信息,详细后述,这里先按流程继续分析。

<3>NimbusOpaqueTokenIntrospector 通过配置好的 url 地址/oauth2/introspect,请求授权服务器。这个请求授权服务器的过程,有 Spring 内部处理,为了方便后续研发的理解,这里列出这个远程服务调用的 HTTP 调用的详细参数说明。

请求响应说明

请求

名称说明
url/oauth2/introspect
MethodPOST
Content-Typeapplication/x-www-form-urlencoded
AuthorizationBasic 值 值为 base64 [客户端 ID]:[客户端密码]

请求参数

名称说明
token访问 token

响应

名称说明
activetrue 表示 token 有效 false 表示无效
client_id客户端 ID
iattoken 的签发时间
exptoken 的过期时间,这个过期时间必须要大于签发时间
scope申请的 scope
token_typetoken 的类型
nbf定义在什么时间之前,该 jwt 都是不可用的
subtoken 所面向的用户
aud接收 tokent 的一方
jtitoken 的唯一身份标识,该值与 token 值应该一致,主要用来作为一次性 token,从而回避重放攻击。

当发起该请求后,后续步骤转到角色为授权服务器的应用上。

授权服务器上:

<4>OAuth2TokenIntrospectionEndpointFilter 拦截 /oauth2/introspect 请求,调用OAuth2TokenIntrospectionAuthenticationProvider校验 token。

<5>OAuth2TokenIntrospectionAuthenticationProvider 处理 token 校验请求,调用 OAuth2AuthorizationService 类获取 OAuth2Authorization 对象。

之后,从 Provider 中返回 token 对应的tokenClaims认证信息。OAuth2TokenIntrospection 对象实际上就是包含tokenClaims认证信息的对象。

再次转到资源服务器:

<6>NimbusOpaqueTokenIntrospector 接收授权服务器的校验 token 响应,组装为 OAuth2AuthenticatedPrincipal 对象。

<7>OpaqueTokenAuthenticationProvider 根据 OAuth2AuthenticatedPrincipal 信息,返回 BearerTokenAuthentication 对象

<8>BearerTokenAuthenticationFilter 设置认证对象 BearerTokenAuthentication 到 SecurityContext 中。

<9>最后,认证信息存储好,会经过 API 接口鉴权的 Filter 进行权限的鉴定,通过后,则进入业务处理的 Controller 。

3.1.3. 注销 token

3.1.3.1. 请求响应说明

请求

名称说明
url/oauth2/revoke
MethodPOST
Content-Typeapplication/x-www-form-urlencoded
AuthorizationBasic 值 值为 base64 [客户端 ID]:[客户端密码]

请求参数

名称说明
token访问 token,必填

响应

Http 状态码为 200 即成功。

3.1.3.2. postman 测试

3.1.3.3. 请求时序图

请求/oauth2/revoke

<1>/oauth2/revoke 接口需要登录才能访问,OAuth2ClientAuthenticationFilter(客户端认证过滤器)拦截请求,调用 OAuth2ClientAuthenticationProvider(客户端认证提供者)对传入的 clientId 和 clientSeceret 进行判断。登录认证成功后,设置认证对象到 SecurityContext 中

<2>登录成功后,OAuth2TokenRevocationEndpointFilter 拦截地址/oauth2/revoke

<3>OAuth2TokenRevocationAuthenticationProvider 处理 token 注销,调用 OAuth2AuthorizationService 类获取 OAuth2Authorization,处理注销。处理注销的方式是对这个 token 增加一个 meta 标签"metadata.token.invalidated"=true,并重新保存 此OAuth2Authorization 对象到 InMemory 内存或者 Redis 中。这里,通过增加 metadata 而不是直接删除存储中的 token 信息,是因为需要非常清晰明确该 token 已经被注销,如果提早删去或清理掉,则授权服务器端就无法判断该 token 最正确的状态(区分不了 token 错误 还是 token 已注销)。

<4>OAuth2TokenRevocationEndpointFilter 设置响应状态为 OK。

3.2. 授权码许可类型

3.2.1. 获取授权码

获取授权码时,会引导用户到授权页面,当未登录时,需要用户登录。登录成功后,如果客户端未配置自动授权,则会显示授权页面,如果配置自动授权,则直接跳过授权页面,302 跳转返回授权码。

这里,再分不同小节,说明 用户登录 - 授权页面 - 获取授权码 的整套流程。

3.2.1.1. 用户登录

1.请求说明

请求格式

名称说明
urlapi/login
MethodPOST
Content-Typeapplication/x-www-form-urlencoded

请求参数

名称说明注意
username用户名
password用户密码

2.postman 测试

执行 用户登录 操作,返回两个有用的信息给浏览器和前端:

  • 登录成功后的 Cookie(含 JSession),后续读取授权码需要从 Session 中读取当前用户的信息;
  • LoginUserDto 的信息(JSON 对象),前端会缓存该用户信息到前端,用于判断当前是否有用户登录,用于给前端根据用户登录状态显示不同的界面。

3.2.1.2. 授权页面

授权页面,是用于呈现给用户,第三方客户端请求获取当前用户的什么权限。作为权限的拥有者(用户)必须要确认是否允许第三方客户端访问自己的信息。

因此,这个授权页面(Code 页面)是需要用户确认并做出选择的。每一个客户端的配置选项中,通过字段 requiry_user_consent 来设置是否展现该页面。

强烈建议对于第三方的客户端,都要求开启授权页面的展示。如果是受信任的第一方客户端,则可以自行决定是否展示。

如果客户端配置表中的 require_user_consent=1 ,用户登录成功后的下一步,前端应当展现授权页面。

请求

名称说明
urloauth2/authorize
MethodGET

请求参数

名称说明注意
client_id客户端 ID
response_type授权码凭证许可固定值为 code
scope授权的 scope 编码 分配多个则用空格分隔

访问上述请求后,会返回授权页面 JSON 数据的请求地址,如下示例。

http://{{AuthorizationServer}}/oauth2/consent?client_id={{client}}&scope={{scope}}&state={{consentState}}

继续转去请求此地址,则会返回 JSON 格式的响应。

JSON 格式:

{
  "clientId": "客户端ID",
  "clientName": "客户端名称",
  "principalName": "登录用户名",
  "state": "state值",
  "scopes": [
    {
      "scope": "scope编码",
      "scopeName": "scope名称",
      "scopeProfileInfo": "scope的简介"
    }
    //...
  ]
}

前端就可以根据上述 JSON 显示授权页面了。

前端根据授权的 JSON 响应,展示页面,在页面中会有一个“允许”的授权控制按钮,如果用户点击“允许”,则会继续发送确认授权的请求。

当用户选择授权的 scope,点击确认授权授权的请求格式如下:

请求

名称说明
urloauth2/authorize
MethodPOST
Content-Typeapplication/x-www-form-urlencoded

请求参数

名称说明注意
client_id客户端 ID
state授权页面响应的 json 中的 state 值
scope授权的 scope 编码 分配多个则参数名有多个同名的 scope 键

这里需要注意,首先 method 从 GET 请求,改为 POST 请求,POST 请求必须注明是 form-urlencoded 格式的表单提交。

第二,这里的 scope 不再是用空格分割,而是会在 form 表单中用相同的键(键值就是 scope)来填写多个不同的 scope。

postman 模拟用户授权提交

可以从截图中看出,响应信息为 302 状态码,并从 Header 的 Location 中读取出授权码

3.2.1.3. 获取授权码

1.请求说明

请求

名称说明
urloauth2/authorize
MethodGET/POST
Content-Typeapplication/x-www-form-urlencoded

请求参数

名称说明注意
client_id客户端 ID
response_type响应类型 固定为 code
scope申请的 scope 多个以空格分割 可选
redirect_uri跳转的 uri 可选draft-ietf-oauth-v2-1-01 地址中本机不能是 localhost,可使用 127.0.0.1,且和客户端中的 redirect_uri 一直

2.响应说明

<1>当客户端配置不需要用户授权同意时,则直接跳过授权页面,直接 302 跳转

http://localhost:8080/callback?code=vNAXkiS70FzBEsZ1wyXYhDC6eRQ8W7T7kQ8ieSR97CsJzNSQxCZmcJzm6wIEAQ_toe7nIqiJ7qHzPLX4HJ-hro647F5j3ow0TX5P-k-OhcbSfzNcj9qR8S03BoOvjxjw

postman 测试获取授权码

使用 Postman 做测试的话,因为它不是一个浏览器,所以需要在 Settings 里面关闭自动跟踪重定向的新 URL 地址,确保在 Header 头的 Location 中能截取出授权码 code 的值。

<2>当客户端配置需要用户授权同意时,则会跳转到授权页面

postman 测试跳转到授权页面

使用 Postman 做测试的话,因为它不是一个浏览器,所以需要在 Settings 里面打开自动跟踪重定向的新 URL 地址以 ,JSON 格式响应。

3.请求序列图

<1>OAuth2AuthorizationEndpointFilter 处理获取授权码的相关逻辑,创建 OAuth2Authorization,调用 OAuth2AuthorizationService 保存。

3.2.2. 用授权码获取 token

1.请求响应格式说明

请求

名称说明
url/oauth2/token
MethodPOST
Content-Typeapplication/x-www-form-urlencoded
AuthorizationBasic 值 值为 base64 [客户端 ID]:[客户端密码]

请求参数

名称说明
grant_type授权类型 固定为 authorization_code
code授权码的值

响应

名称说明
access_token访问 token
refresh_token刷新 token
scope申请的 scope
token_typetoken 的类型
expires_in访问 token 有效期,单位为秒

2.postman 测试

3.请求序列图 

客户端发起请求/oauth2/token

<1>对客户端信息进行认证

/oauth2/token接口需要客户端认证通过才能访问,OAuth2ClientAuthenticationFilter(客户端认证过滤器)拦截请求,调用OAuth2ClientAuthenticationProvider(客户端认证管理器的提供者)对传入的client_idclient_secret进行判断。登录认证成功后,设置认证成功的结果(OAuth2ClientAuthenticationToken,内含客户端信息的RegisteredClient结果)到SecurityContext中。然后跳到下一步的过滤器中。

<2>对客户端信息进行二次认证

过滤器OAuth2TokenEndpointFilter继续拦截此请求,然后在颁发 Token 之前,请求OAuth2AuthorizationCodeAuthenticationProvider(授权码凭据许可认证管理器的提供者)的authenticate()方法进行第二次认证。因为第一步的OAuth2ClientAuthenticationFilter已经校验过client_secret,这里主要对 client 的授权模式是否吻合,以及 scope 的授权范围进行校验就通过了。

OAuth2TokenEndpointFilter中,调用 OAuth2XxxxAuthenticationProvider 的 authenticate() 方法进行认证是固定流程。实际会根据不同的grant_type去选择调用不同的 OAuth2XxxxAuthenticationProvider 进行认证。因此,对客户端信息进行了二次认证,第一次和第二次的认证的职责是不同的。

<3>创建访问 Token

<3.1>开始颁发 Token:增强 Token 中包含的信息

首先是要确定 Token 中包含的信息。在OAuth2AuthorizationCodeAuthenticationProvider中通过 OAuth2TokenCustomizer 定制 token 相关信息(定制 JwtEncodingContext 对象的 Claims 属性)

<3.2>开始颁发 Token:修改 tokenValue 值为 uuid 格式

然后JwtEncoder 根据定制之后的JwtEncodingContext,生成 jwtAccessToken,这里的 jwtAccessToken 可以认为只是一个以 jwt 为容器存储了 token 的不同属性信息的候选 AccessToken

<3.3>开始颁发 Token:正式颁发 OAuth2AccessToken

之后,真正颁发 AccessToken。通过 jwtAccessToken 构建 OAuth2AccessToken 对象,使用了 jwtAccessToken 的 tokenValue 值(该值是 UUID)。OAuth2AccessToken 才是真正要颁发的 AccessToken 对象。

<4>创建刷新 Token

如果客户端支持刷新 Token,则会创建OAuth2RefreshToken

<5>持久化 Token 及认证过程中的所有信息

为了在颁发 Token 后,能对 Token 进行验证其合法性,以及返回 Token 包含的信息,因此需要对 Token 及其相关的信息进行持久化。

结合OAuth2AccessTokenjwtAccessToken这两个对象,把它们中相关的属性抽出构建为OAuth2Authorization对象(最终的这个对象包含了客户端信息、token 信息、GrantType 信息、authorizedScopes 信息,token 中的所有 Claims 信息的集合),然后通过接口OAuth2AuthorizationService保存OAuth2Authorization对象,因为这个对象包含的信息最完整,这里保存下来后便于后续对 Token 进行校验。

<6>返回响应信息

最终,OAuth2AuthorizationCodeAuthenticationProvider返回新 New 的OAuth2AccessTokenAuthenticationToken对象到OAuth2TokenEndpointFilter,这个 Filter 过滤器处理转换为返回给前端的响应OAuth2AccessTokenResponse

OAuth2AccessTokenResponse 对象

3.2.3. 刷新 token

1.请求响应格式说明

请求

名称说明
url/oauth2/token
MethodPOST
Content-Typeapplication/x-www-form-urlencoded
AuthorizationBasic 值 值为 base64 [客户端 ID]:[客户端密码]

请求参数

名称说明
grant_type授权类型 固定为 refresh_token
refresh_token刷新 refresh_token 的值

响应

名称说明
access_token访问 token
refresh_token刷新 token
scope申请的 scope
token_typetoken 的类型
expires_in访问 token 有效期,单位为秒

2.postman 测试

3.请求时序图

请求/oauth2/token?grant_type=refresh_token

<1>/oauth2/token 接口需要登录才能访问,OAuth2ClientAuthenticationFilter(客户端认证过滤器)拦截请求,调用 OAuth2ClientAuthenticationProvider(客户端认证提供者)对传入的 clientId 和 clientSeceret 进行判断。登录认证成功后,设置认证对象到 SecurityContext 中

<2>登录成功后,OAuth2TokenEndpointFilter拦截地址/oauth2/token,请求 OAuth2RefreshTokenAuthenticationProvider(刷新 Token 认证提供者)

<3>OAuth2RefreshTokenAuthenticationProvider 根据 refresh_token,通过 OAuth2AuthorizationService 找到 OAuth2Authorization 对象

<4>OAuth2RefreshTokenAuthenticationProvider中生成新的访问 Token 设置到OAuth2Authorization对象中,生成访问 token 的处理过程和获取访问 token 时处理逻辑一致

<5>OAuth2TokenEndpointFilter 将返回的 OAuth2AccessTokenAuthenticationToken处理转换为返回给前端的响应OAuth2AccessTokenResponse

3.2.4. 校验 token,访问需要 API 权限的接口

同客户端模式,区别就是第 5 和第 6 步中的对象属性不一样

<5>OAuth2TokenIntrospection 对象

3.2.5. 注销 token

同客户端模式

3.3. 资源拥有者凭据许可

从“资源拥有者凭据许可”这个命名上,你可能就已经理解它的含义了。没错,资源拥有者的凭据,就是用户的凭据,就是用户名和密码。可见,这是最糟糕的一种方式。那为什么 OAuth 2.0 还支持这种许可类型,而且编入了 OAuth 2.0 的规范呢?

我们先来思考一下。正如上面我提到的,小兔此时就是京东官方出品的一款软件,小明也是京东的用户,那么小明其实是可以使用用户名和密码来直接使用小兔这款软件的。原因很简单,那就是这里不再有“第三方”的概念了。

但是呢,如果每次小兔都是拿着小明的用户名和密码来通过调用 Web API 的方式,来访问小明店铺的订单数据,甚至还有商品信息等,在调用这么多 API 的情况下,无疑增加了用户名和密码等敏感信息的攻击面。

如果是使用了 token 来代替这些“满天飞”的敏感信息,不就能很大程度上保护敏感信息数据了吗?这样,小兔软件只需要使用一次用户名和密码数据来换回一个 token,进而通过 token 来访问小明店铺的数据,以后就不会再使用用户名和密码了。

接下来,我们一起看下这种许可类型的流程,如下图所示:

下图的“第三方”实际上应为“第一方”

3.3.1. 获取访问 token

1.请求响应说明

请求格式

名称说明
url/oauth2/token
MethodPOST
Content-Typeapplication/x-www-form-urlencoded
Authorization格式为:Basic 。 为 base64 编码的 {client_id}:{client_secret}。

请求参数

名称说明
grant_type授权许可类型。 固定为 password
scope可选。申请的权限范围
username用户名 必须
password用户密码 必须

响应

名称说明
access_token访问 token
refresh_token刷新 token
scope申请的 scope
token_typetoken 的类型
expires_in访问 token 有效期,单位为秒

2.postman 测试

请求

POST /oauth2/token?username=guest&password=guest&grant_type=password&scope=test1 test2 HTTP/1.1
Host: localhost:8080
Authorization: Basic Y2xpZW50OjEyMzQ1Ng==

响应

{
  "access_token": "747558ce-e130-4efe-b73e-7a0f5789a571",
  "refresh_token": "e6DEmAQt4-1t-BrlqHz1mCtyne2ujD5drpwk_ohSQqqnaEiEgJq",
  "scope": "test2 test1",
  "token_type": "Bearer",
  "expires_in": 7200
}

3.请求序列图

核心流程和授权码基本一致,不同之处如下:

1.OAuth2ResourceOwnerPasswordAuthenticationProvider中会调用AuthenticationManager验证用户名密码是否正确。

2.在授权码的第<5>步中持久化 Token 及认证过程中的所有信息 OAuth2Authorization 对象属性值不一样

3.3.2. 刷新 token

同授权码处理模式基本一样

3.3.3. 校验 token,访问需要 API 权限的接口

同授权码处理模式基本一样

3.3.4. 注销 token

同授权码处理模式基本一样

6. 附录

Spring Security OAuth

https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Migration-Guide

Announcing the Spring Authorization Server

https://github.com/spring-projects-experimental/spring-authorization-server

oauth2.0的授权流程详解 - charlyFeng - 博客园

  • 14
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
### 回答1: spring-security-oauth2-authorization-server是一个基于Spring SecurityOAuth2授权服务器,用于管理和授权访问受保护的资源。它提供了一组API和工具,使得开发人员可以轻松地实现OAuth2授权服务器,并支持多种授权方式和流程。该授权服务器可以与其他Spring框架集成,例如Spring BootSpring Cloud,以便更好地管理和保护应用程序的资源。 ### 回答2: Spring Security OAuth2 Authorization Server是一个强大的用户授权服务,它可以让用户安全地授权他们的敏感信息,以便客户端应用程序可以访问他们的资源。 它基于Spring的安全框架构建,与OAuth2协议规范兼容。OAuth2是一个授权协议,它允许用户授权客户端应用程序在用户的名义上访问他们的资源。Spring Security OAuth2 Authorization Server提供了多种授权模式,包括基于密码授权、刷新令牌和授权码授权等。 该服务还提供了一组API组件,使开发人员可以轻松地创建客户端应用程序并管理授权和令牌。通过使用Spring Security OAuth2 Authorization Server,开发人员可以保持持久的跨应用程序用户会话状态,并方便地跟踪和管理资源的访问。 Spring Security OAuth2 Authorization Server提供了一个安全的授权层,可以使用Token转义解决跨域请求的问题,支持多个授权模式,并支持动态客户端注册。此外,该服务还提供了一个管理界面,可用于管理授权信息、令牌和客户端应用程序的访问权限等。 最后,Spring Security OAuth2 Authorization Server还提供了一组可扩展的插件,可以通过它们扩展和定制授权流程和授权服务。这些插件可以轻松地扩展并与其他技术进行集成。 ### 回答3: Spring Security OAuth2 Authorization ServerSpring Security生态系统中的一个组件,是一种用于构建并管理OAuth2授权服务的框架。OAuth2是一种用于保护API、防止破坏攻击的开放标准,它提供了一种用于分离用户、应用程序和资源服务器之间的身份验证和授权的机制。它允许用户授权第三方应用程序访问他们在其他应用程序和服务上存储的服务。OAuth2授权服务是一个负责认证用户信息并授权访问令牌的服务器。 Spring Security OAuth2 Authorization Server提供一个开箱即用的OAuth2认证服务器,它提供了一些默认的配置和管理OAuth2令牌的选项。它还提供了一些简单和可扩展的API以支持OAuth2流程的不同阶段,从而帮助开发人员方便地创建和配置基于OAuth2的应用程序。 Spring Security OAuth2 Authorization Server的主要功能包括: 1. 提供一个可扩展的API,以便在不同的OAuth2流程阶段进行修改。 2. 附带默认的令牌存储实现。 3. 允许自定义授权和令牌端点。 4. 提供了可插拔的身份验证和授权机制,开发人员可以方便地配置和管理。 5. 允许开发人员创建和使用自定义的令牌存储实现。 6. 允许开发人员基于OAuth2协议为应用程序提供安全性。 总之,Spring Security OAuth2 Authorization Server为开发人员提供了一个可扩展的和可定制的OAuth2认证服务器,使得开发人员可以方便地构建基于OAuth2的应用程序。它简化了OAuth2认证的过程,帮助开发人员快速构建和部署安全且可靠的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tof21

支持原创

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值