# oauth2 配置

使用 oauth2 功能首先需要按照第六章中的步骤开启 spring security 的相关功能。

快速启动

1 在项目中加入 oauth 相关的依赖

<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>2.2.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.yishuifengxiao.common</groupId>
    <artifactId>common-spring-boot-starter</artifactId>
    <version>4.2.1</version>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

2 在项目加入以下代码

    @Configuration
	public class CustomOauth2Config extends Oauth2Config{

	}

3 加上@EnableResourceServer@EnableAuthorizationServer注解

完全开启示例代码如下:

@Configuration
@EnableWebSecurity
@EnableResourceServer
@EnableAuthorizationServer
public class SecurityConfig extends AbstractSecurityConfig {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		super.configure(http);
	}

	@Configuration
	public class CustomOauth2Config extends Oauth2Config{

	}

}

4 实现ClientDetailsService接口,完成自己的认证逻辑

完成自定义实现后,按照名字customClientDetailsService向spring中注入一个ClientDetailsService实例

【特别注意】在用户未按照(4)中的步骤配置自己的授权逻辑时,组件会默认进行一个缺省实现。在缺省实现的情况下,用户能使用任意用户名配合密码(12345678)进行登录

# 四种授权方式

# 密码模式

POST /oauth/token HTTP/1.1
     Host: oauth2.yishuifengxiao.com
     Authorization: Basic fdsfdsfdsfds
     Content-Type: application/x-www-form-urlencoded

     grant_type=password&username=johndoe&password=A3ddj3w

在请求中,各参数的含义如下

  • grant_type:表示授权类型,此处的值固定为"password",必选项。
  • username:表示用户名,必选项。
  • password:表示用户的密码,必选项。
  • scope:表示权限范围,可选项。
  • Authorization: 请求头参数 ,值是 clientId:clientSecret 经过 base64 编码后的值

下面是一个响应的例子

{
    "access_token": "BDF867DE69F05143C709",
    "token_type": "bearer",
    "refresh_token": "d7cda8fb15714209a9f9f3b039a0034f",
    "expires_in": 43199,
    "scope": "read write trust",
    "client_id": "yishui"
}

# 客户端模式

POST /oauth/token HTTP/1.1
     Host: oauth2.yishuifengxiao.com
     Authorization: Basic fdsfdsfdsfds
     Content-Type: application/x-www-form-urlencoded

     grant_type=client_credentials

在本请求中,各参数的含义如下

  • grant_type:表示授权类型,此处的值固定为"client_credentials",必选项。
  • Authorization: 请求头参数 ,值是 clientId:clientSecret 经过 base64 编码后的值

下面是一个响应的例子

{
    "access_token": "BDF867DE69F05143D3BF",
    "token_type": "bearer",
    "expires_in": 43199,
    "scope": "read write trust",
    "client_id": "yishui"
}

同密码模式相比,客户端模式的响应中缺少了 refresh_token 参数

# 授权码模式

授权码模式首先需要保证 spring security 的登陆功能正常可用。只有开启 spring security 的登陆功能可用,才能开启授权码功能。

先访问一下请求

GET /oauth/authorize?response_type=code&client_id=yishui&state=xyz
&redirect_uri=http://demo.yishuifengxiao.com/demo HTTP/1.1
Host: oauth2.yishuifengxiao.com

在本请求中,各参数的含义如下:

  • code:表示授权码,必选项。该码的有效期应该很短,通常设为 10 分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端 ID 和重定向 URI,是一一对应关系。
  • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
  • client_id: 用户的 client_id

在进行此请求时,假如用户没有登录,spring security 会进行拦截,因此需要用户先进行登录。

在正常情况下,访问以上请求会被重定向到

http://demo.yishuifengxiao.com/demo?code=fsfsdf &state=xyz

服务器回应客户端的 URI,包含以下参数:

  • code:表示授权码,必选项。该码的有效期应该很短,通常设为 10 分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端 ID 和重定向 URI,是一一对应关系。
  • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。

通过上面的请求得到了code以后,用户需要使用下面请求获取到授权码

POST /oauth/token HTTP/1.1
Host: oauth2.yishuifengxiao.com
Authorization: Basic fdsfdsfdsfds
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=fsfsdf
&redirect_uri=demo.yishuifengxiao.com/demo

在本请求中,各参数的含义如下:

  • grant_type:表示使用的授权模式,必选项,此处的值固定为"authorization_code"。
  • code:表示上一步获得的授权码,必选项。
  • redirect_uri:表示重定向 URI,必选项,且必须与 A 步骤中的该参数值保持一致。
  • client_id:表示客户端 ID,必选项。

# 简化模式

GET /oauth/authorize?response_type=token&client_id=yishui&state=xyz
        &redirect_uri=http://demo.com/demo    HTTP/1.1
    Host: server.example.com

在本请求中,各参数的含义如下:

  1. response_type:表示授权类型,此处的值固定为"token",必选项。
  2. client_id:表示客户端的 ID,必选项。
  3. redirect_uri:表示重定向的 URI,可选项。
  4. scope:表示权限范围,可选项。
  5. state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

# 刷新 token

POST /oauth/token HTTP/1.1
     Host: oauth2.yishuifengxiao.com
     Authorization: Basic fdsfdsfdsfds
     Content-Type: application/x-www-form-urlencoded

     grant_type=refresh_token&refresh_token=sdff

请求中个参数的含义:

  • granttype:表示使用的授权模式,此处的值固定为"refreshtoken",必选项。
  • refresh_token:表示早前收到的更新令牌,必选项。
  • scope:表示申请的授权范围,不可以超出上一次申请的范围,如果省略该参数,则表示与上一次一致。

# access_token 使用

通过 前面的方法获取到 access_token 之后,一般有两种使用方法

  • 将 access_token 做为请求参数携带在 url 参数上

http://demo.yishuifengxiao.com/user/123?access_token=获得到的access_token

  • 将 access_token 做为请求参数放在请求头中

在所有需要授权的请求的请求头里都携带上参数 Authorization=Bearer 获得到的 access_token

在通用组件中,由于对access_token进行了深度处理,因此用户可以access_token通过易水工具包里的 DES 工具饭解析出 token 里携带的信息。

在解密时需要使用的密钥由【安全管理】中设置的yishuifengxiao.security.secret-key属性值决定。

下面是一个 access_token 的解密信息示例

{
    "username": "yishui",
    "clientId": "admin",
    "roles": [
        "ROLE_USER",
        "admin"
    ],
    "grantType": "password"
}

解密信息的各参数的解释:

  • username: 用户登录时使用到的用户名(在客户端模式下该值为空)
  • clientId: 用户登录时使用的 clientId(在简化模式下该值为空)
  • roles: 此登录用户拥有的角色(即此用户的 authorities)
  • grantType:access_token 对应的授权类型

access_token反解析出用户信息仅限于本组件,原生的 oauth2 的access_token不支持此功能

# 授权资源管理

# 基础概念

本组件中 oauth2 的资源由以下几部分组成:

  1. 非管理资源
  2. 匿名资源
  3. 自定义授权逻辑资源
  4. 保护资源
  5. 游离资源

oauth2 中的授权资源与 spring security 中授权资源既有重合又有不同的地方。对于 spring security 中非管理资源自定义授权逻辑资源以及匿名资源保护资源的概念依然保持一致,在继承了 spring security 资源管理概念的基础上,并且增加 游离资源的概念。

游离资源

需要经过 spring security 权限管理,但是不在 oauth2 权限管理范围之内,它依旧是 spring security 中保护资源的一部分。

在 oauth2 的资源体系中

所有资源  = 非游离资源 + 游离资源
          = 非管理资源 + 自定义授权逻辑资源 + 匿名资源 + 保护资源 + 游离资源

# 游离资源

组件里默认游离资源资源为

 /oauth/\*\*
 yishuifengxiao.security.handler.suc.redirectUrl        #默认值为 index
 yishuifengxiao.security.core.formActionUrl             #默认值为 /auth/form
 yishuifengxiao.security.core.loginOutUrl               #默认值为 /loginOut
 yishuifengxiao.social.filterProcessesUrl+/+yishuifengxiao.social.qq.providerId
 yishuifengxiao.social.filterProcessesUrl+/+yishuifengxiao.social.weixin.providerId

除了这些默认的系统配置外,用户还可以根据项目需要配置自己的资源路径

yishuifengxiao.security.oauth2.excludes.demo1=/aaa
yishuifengxiao.security.oauth2.excludes.demo2=/cc/**,/dsd/**

在上面的示例配置中 demo1demo2 由用户自行配置,可以配置成任意符合规范的值,这些配置属性的值即为需要配置的资源,多个授权资源间用半角逗号分开。

# 流程处理器

与 spring security 相比,oauth2 在 spring security 的基础上增加两个流程处理器 权限拒绝处理器资源异常处理器。他们的处理逻辑与 spring security 中流程处理器的逻辑完全一致,因此在这里不做过多介绍。

# 权限拒绝处理器

权限拒绝处理器 一般会在用户无权访问资源(如 401)的情况下触发

默认的属性配置如下

yishuifengxiao.security.handler.denie.returnType=atuo
yishuifengxiao.security.handler.denie.redirectUrl=/index

在组件中,系统默认由CustomAuthenticationSuccessHandler处理权限拒绝后的逻辑。处理流程如下:

  1. 发送一个名为 AccessDeniedEvent的消息事件,告知系统已经登陆成功
  2. 将导致权限拒绝的原因存储到 session 中,存储的键名为 yishuifengxiao.msg.denie
  3. 将 引起权限拒绝的资源的 url 地址存储到 session 中,存储的键名为 yishuifengxiao.denie.url
  4. 获取系统配置的登权限拒绝处的处理方式
  5. 将权限拒绝处后逻辑交给协助处理器处理

在某些情况下,如果用户希望自定义资源异常后的处理逻辑, 可以通过在 spring 的上下文中注入一个名为accessDeniedHandlerAccessDeniedHandler实例即可

示例代码如下

@Bean("accessDeniedHandler")
public AccessDeniedHandler accessDeniedHandler(
    ProcessHandler customHandle, ApplicationContext context) {
		CustomAccessDeniedHandler handler = new CustomAccessDeniedHandler();
		handler.setSecurityProperties(securityProperties);
		handler.setCustomHandle(customHandle);
		handler.setContext(context);
		return handler;
}

# 资源异常处理器

资源异常处理器 一般在用户访问资源时忘记携带 token 或者携带的 token 信息已过期的情况下触发。

默认的属性配置如下


yishuifengxiao.security.handler.exception.returnType=atuo
yishuifengxiao.security.handler.exception.redirectUrl=/index

在组件中,系统默认由ExceptionAuthenticationEntryPoint处理权限拒绝后的逻辑。处理流程如下:

  1. 发送一个名为 ExceptionAuthenticationEntryPointEvent的消息事件,告知系统已经登陆成功
  2. 将导致权限拒绝的原因存储到 session 中,存储的键名为 yishuifengxiao.msg.exception
  3. 将 引起权限拒绝的资源的 url 地址存储到 session 中,存储的键名为 yishuifengxiao.exception.url
  4. 获取系统配置的登权限拒绝处的处理方式
  5. 将权限拒绝处后逻辑交给协助处理器处理

在某些情况下,如果用户希望自定义资源异常后的处理逻辑, 可以通过在 spring 的上下文中注入一个名为exceptionAuthenticationEntryPointAuthenticationEntryPoint实例即可

示例代码如下

@Bean("exceptionAuthenticationEntryPoint")
public AuthenticationEntryPoint exceptionAuthenticationEntryPoint(
    ProcessHandler customHandle,ApplicationContext context) {
    ExceptionAuthenticationEntryPoint point = new ExceptionAuthenticationEntryPoint();
    point.setCustomHandle(customHandle);
    point.setSecurityProperties(securityProperties);
    point.setContext(context);
    return point;
}

# 异常转换

在本组件中,默认由Auth2ResponseExceptionTranslator实现 oauth2 中的异常转换。如果需要自定义异常转换过程,只需要在 spring 的上下文中注入一个名为auth2ResponseExceptionTranslatorWebResponseExceptionTranslator实例即可。

示例代码如下:

	@Bean("auth2ResponseExceptionTranslator")
	public WebResponseExceptionTranslator auth2ResponseExceptionTranslator() {
		return new Auth2ResponseExceptionTranslator();
	}

# token生成策略

在一般情况下,只需要使用系统默认的 token 生成策略即可。但是在某些需求的情况下,如需要在 oauth2 模式下限制多终端登录等,即需要自定义 token 生成策略了,此时,只需要在 spring 的上下文注入一个名为authorizationServerTokenServicesAuthorizationServerTokenServices示例即可。

示例代码如下:

    /**
     * 自定义token生成规则
     *
     * @param tokenStore
     * @param clientDetailsService
     * @param accessTokenEnhancer
     * @param authenticationManager
     * @return
     */
    @Bean("authorizationServerTokenServices")
    public AuthorizationServerTokenServices authorizationServerTokenServices(TokenStore tokenStore,
    		ClientDetailsService clientDetailsService, TokenEnhancer accessTokenEnhancer,
    		AuthenticationManager authenticationManager) {
    	DefaultTokenServices tokenServices = new DefaultTokenServices();
    	tokenServices.setTokenStore(tokenStore);
    	tokenServices.setClientDetailsService(clientDetailsService);
    	tokenServices.setTokenStore(tokenStore);
    	tokenServices.setAuthenticationManager(authenticationManager);
    	return tokenServices;
    }

DefaultTokenServices中,用户就可以自定义 token 生成策略。

# token存储策略

在组件中,token的存储方式有三种

  1. 在系统中没有配置reids时默认存储在内存中,由 InMemoryTokenStore负责处理
  2. 在系统中配置有redis连接时默认存储在redis里,由RedisTokenStore负责处理
  3. 自定义token存储策略

在自定义token存储策略,只需要向spring 上下文中注入一个名为 tokenStoreTokenStore实例即可。 示例如下:

	@Bean("tokenStore")
	public TokenStore tokenStore() {
		return new InMemoryTokenStore();
	}
Last Updated: 1/13/2020, 9:58:22 PM