抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

OAuth2授权码模式

授权码模式

授权流程

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

使用场景

  1. 授权码模式是最常见的一种授权模式,在oauth2.0内是最安全和最完善的。
  2. 适用于所有有Server端的应用,如Web站点、有Server端的手机客户端。
  3. 可以得到较长期限授权。

图解

  • 授权码模式是最常见常用的模式,我们所熟悉的微博,QQ 等都是这种模式。
  • 另外也是最繁琐的一种方式,如果弄懂了这个相信接下来的三种类型都会迎刃而解。
  • 这种模式和其他最大的区别就在于是否有授权码这个步骤。

授权码示例

授权服务器

创建auth-server服务

引入POM文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
配置文件

注意使用了配置中心,eureka配置存放在配置中心

application

创建application.properties

1
2
server.port=9988
spring.application.name=auth-server
bootstrap

创建bootstrap.properties

1
2
3
4
5
6
7
8
9
10
#注册中心地址
spring.cloud.config.uri=http://192.168.64.128:8899
#配置文件分支
spring.cloud.config.label=master
# 配置文件名称
spring.cloud.config.name=application
# 配置文件环境
spring.cloud.config.profile=dev
#如果连接不上获取配置有问题,快速响应失败
spring.cloud.config.fail-fast=true
启动类
1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableEurekaClient
public class AuthApplication {

public static void main(String[] args) {
SpringApplication.run(AuthApplication.class);
}
}
授权服务配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/**
* 授权服务器配置
**/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

@Autowired
private AuthenticationManager authenticationManager;

@Autowired
UserDetailsService userDetailsService;

// 使用最基本的InMemoryTokenStore生成token
@Bean
public TokenStore memoryTokenStore() {
return new InMemoryTokenStore();
}


/**
* 配置客户端详情服务
* 客户端详细信息在这里进行初始化,你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息
* 1.授权码模式(authorization code)
* 2.简化模式(implicit)
* 3.密码模式(resource owner password credentials)
* 4.客户端模式(client credentials)
* ClientDetailsServiceConfigurer
*
* @param clients
* @throws Exception
*/
@Override

public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("order-server")//用于标识用户ID
.authorizedGrantTypes("authorization_code", "refresh_token")//授权方式
.resourceIds("order-server")
.authorities("authorization_code")
//跳转客户端地址
.redirectUris("http://baidu.com")
.scopes("test")//授权范围
//客户端安全码,secret密码配置从 Spring Security 5.0开始必须以 {bcrypt}+加密后的密码 这种格式填写;
.secret(PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("123456"))
.accessTokenValiditySeconds(1200)
.refreshTokenValiditySeconds(50000);


}

/**
* 用来配置令牌端点(Token Endpoint)的安全约束.
*
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
/* 配置token获取合验证时的策略 允许表单认证 */
security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()").allowFormAuthenticationForClients();
}

/**
* 用来配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services)
*
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 配置tokenStore,需要配置userDetailsService,否则refresh_token会报错
endpoints.authenticationManager(authenticationManager).tokenStore(memoryTokenStore()).userDetailsService(userDetailsService).allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
}
}
spring security配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* 配置spring security
**/
@EnableWebSecurity//开启权限验证
public class SecurityConfig extends WebSecurityConfigurerAdapter {

/**
* 配置这个bean会在做AuthorizationServerConfigurer配置的时候使用
*
* @return
* @throws Exception
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}

/**
* 配置用户
* 使用内存中的用户,实际项目中,一般使用的是数据库保存用户,具体的实现类可以使用JdbcDaoImpl或者JdbcUserDetailsManager
*
* @return
*/
@Bean
@Override
protected UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("admin").password(PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("admin")).authorities("USER").build());
return manager;
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService());
}
}

启动测试

获取授权码

在有了服务提供商之后,我们就可以根据OAuth的规则,来要求用户给予授权,所以这里需要第三方应用去

请求参数
参数 描述
localhost 8080这里是我服务的地址以及端口,根据每个人的情况是不同的
/oauth/authorize 这个是Spring Security OAuth2默认提供的接口
response_type 表示授权类型,必选项,此处的值固定为”code”
client_id 表示客户端的ID,必选项。这里使用的是项目启动时,控制台输出的security.oauth2.client.clientId,当然该值可以在配置文件中自定义
redirect_uri 表示重定向URI,可选项。即用户授权成功后,会跳转的地方,通常是第三方应用自己的地址
scope 表示申请的权限范围,可选项。这一项用于服务提供商区分提供哪些服务数据
state 表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。这里没有使用到该值
身份验证
1
http://127.0.0.1:9988/oauth/authorize?response_type=code&client_id=order-server&redirect_uri=http://baidu.com

这里我们访问到接口后,会出现如下的界面

如果没有登录,浏览器会重定向到登录界面

该界面主要是用于用户登录的,不然怎么知道想要哪个用户的数据呢?

服务授权

输入用户名和密码(admin/admin)点击登录,这时会进入授权页

这里就是要求用户授权的界面了,有点类似于我们使用QQ进行第三方登录时候的界面。上面写有了是哪一个第三方应用需要哪些数据,我们这里就点确认授权,这里就会根据配置的redirect_uri进行跳转,并且是带有一个参数的。

点击授权,浏览器会从定向到回调地址上,携带code参数

授权码是 sNMfYR

这个code就是下一步第三方应用向服务器申请令牌使用的

获取令牌

这里我们拿着上一步获取到的code,以及项目初始化时打印的clientId和secret去获取Token,这里需要使用POST方法。

请求参数

请求的Header中有一个Authorization参数,该参数的值是Basic + (clientId:secret Base64值)

参数 描述
grant_type 表示使用的授权模式,必选项,此处的值固定为”authorization_code”。
code 表示上一步获得的授权码,必选项。
redirect_uri 表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
client_id 表示客户端ID,必选项。
获取Token
1
http://localhost:9988/oauth/token?grant_type=authorization_code&code=sNMfYR&client_id=order-server&client_secret=123456&redirect_uri=http://baidu.com

如果请求成功,就可以顺利的拿到Token

返回数据格式如下

1
2
3
4
5
6
7
{
"access_token": "353f4d37-2668-4f0d-b7a7-ded3350258d0",
"token_type": "bearer",
"refresh_token": "bd73e4f0-08f8-456c-b96f-4019aa0ad2e7",
"expires_in": 1199,
"scope": "test"
}
返回参数
参数 描述
access_token 表示访问令牌,必选项
token_type 表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
expires_in 表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
refresh_token 表示更新令牌,用来获取下一次的访问令牌,可选项。
scope 表示权限范围,如果与客户端申请的范围一致,此项可省略。

再次请求发现错误了,这个授权码只能使用一次,如想要使用还需要从头继续申请

校验授权码

请求所需参数:token

1
http://127.0.0.1:9988/oauth/check_token?token=e3fa343f-11b7-4c44-9ece-af7c7c43cb49

调用发现出现401 错误,没有权限,这个时候需要进行baseAuth认证

其中 username是 client_id,密码是配置的 secret

配置完成再次访问

返回如下信息校验成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"aud": [
"order-server"
],
"user_name": "admin",
"scope": [
"test"
],
"active": true,
"exp": 1590648560,
"authorities": [
"USER"
],
"client_id": "order-server"
}

我们故意把token改错试试

刷新token

请求所需参数:grant_type、refresh_token、client_id、client_secret
其中grant_type为固定值:grant_type=refresh_token

1
http://localhost:9988/oauth/token?grant_type=refresh_token&refresh_token=ac8a2ff7-be4b-4d22-8dc6-93ddbfc9d5ce&client_id=order-server&client_secret=123456

资源服务器

引入POM文件
1
2
3
4
5
6
security.oauth2.resource.token-info-uri=http://127.0.0.1:9988/oauth/check_token
security.oauth2.client.clientId=order-server
security.oauth2.client.user-authorization-uri=http://127.0.0.1:9988/oauth/authorize
security.oauth2.client.client-secret=123456
security.oauth2.client.access-token-uri=http://127.0.0.1:9988/oauth/token
security.oauth2.client.scope=test
启动类配置

增加@EnableResourceServer注解

1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootApplication
@EnableEurekaClient
//开启Hystrix断路器功能
@EnableHystrix
//开启资源服务器
@EnableResourceServer
public class OrderApplication {

public static void main(String[] args) {
SpringApplication.run(OrderApplication.class);
}
}
测试

访问测试接口

http://127.0.0.1:8083/order/createorder/1?access_token=b8a3d75a-a3d7-4ebc-9f1d-e880d8a48e27

测试成功

将token改错误

增加redis存储

授权服务器配置

引入POM

加入redis相关jar

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置文件

application.properties增加redis配置

1
2
3
4
# redis 配置
spring.redis.host=192.168.64.128
spring.redis.port:6379
spring.redis.database:0
授权服务配置

授权配置类加入Redis配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/**
* 授权服务器配置
**/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

/**
* redis工厂,默认使用lettue
*/
@Autowired
public RedisConnectionFactory redisConnectionFactory;

@Autowired
private AuthenticationManager authenticationManager;

@Autowired
UserDetailsService userDetailsService;

// 使用最基本的InMemoryTokenStore生成token
@Bean
public TokenStore memoryTokenStore() {
return new InMemoryTokenStore();
}


/**
* 配置客户端详情服务
* 客户端详细信息在这里进行初始化,你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息
* 1.授权码模式(authorization code)
* 2.简化模式(implicit)
* 3.密码模式(resource owner password credentials)
* 4.客户端模式(client credentials)
* ClientDetailsServiceConfigurer
*
* @param clients
* @throws Exception
*/
@Override

public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("order-server")//用于标识用户ID
//支持 授权码、密码两种授权模式,支持刷新token功能
.authorizedGrantTypes("authorization_code", "refresh_token")//授权方式
.resourceIds("order-server")
.authorities("authorization_code")
//跳转客户端地址
.redirectUris("http://baidu.com")
.scopes("test")//授权范围
//客户端安全码,secret密码配置从 Spring Security 5.0开始必须以 {bcrypt}+加密后的密码 这种格式填写;
.secret(PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("123456"))
.accessTokenValiditySeconds(1200)
.refreshTokenValiditySeconds(50000);


}

/**
* 用来配置令牌端点(Token Endpoint)的安全约束.
*
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
/* 配置token获取合验证时的策略 允许表单认证 */

security.allowFormAuthenticationForClients().
//客户端token调用许可
tokenKeyAccess("permitAll()").
//客户端校验token访问许可
checkTokenAccess("isAuthenticated()");
}

/**
* 用来配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services)
*
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 配置tokenStore,需要配置userDetailsService,否则refresh_token会报错
endpoints.authenticationManager(authenticationManager).
//配置用户服务
userDetailsService(userDetailsService).
allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST).
//配置token存储的服务与位置
tokenServices(tokenService()).
tokenStore(tokenStore());
}

@Bean
public TokenStore tokenStore() {
//使用redis存储token
RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);
//设置redis token存储中的前缀
redisTokenStore.setPrefix("auth-token:");
return redisTokenStore;
}

@Bean
public DefaultTokenServices tokenService() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
//配置token存储
tokenServices.setTokenStore(tokenStore());
//开启支持refresh_token,此处如果之前没有配置,启动服务后再配置重启服务,可能会导致不返回token的问题,解决方式:清除redis对应token存储
tokenServices.setSupportRefreshToken(true);
//复用refresh_token
tokenServices.setReuseRefreshToken(true);
//token有效期,设置12小时
tokenServices.setAccessTokenValiditySeconds(12 * 60 * 60);
//refresh_token有效期,设置一周
tokenServices.setRefreshTokenValiditySeconds(7 * 24 * 60 * 60);
return tokenServices;
}
}

资源服务器

引入POM

加入redis相关jar

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置文件

application.properties增加redis配置

1
2
3
4
# redis 配置
spring.redis.host=192.168.64.128
spring.redis.port:6379
spring.redis.database:0
资源服务器配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

@Configuration
//开启资源服务器
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

@Autowired
private RedisConnectionFactory redisConnectionFactory;

@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
//无状态
resources.stateless(true);
//设置token存储
resources.tokenStore(tokenStore()).resourceId("order-server");
}

/**
* 设置token存储,这一点配置要与授权服务器相一致
*/
@Bean
public RedisTokenStore tokenStore() {
RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);
redisTokenStore.setPrefix("auth-token:");
return redisTokenStore;
}
}

自动续签

主要思路

  1. 首先用过期token访问受拦截资源
  2. 认证失败返回401的时候调用异常处理器
  3. 通过异常处理器结合refresh_token进行token的刷新
  4. 刷新成功则通过请求转发(request.getRequestDispatcher)的方式再次访问受拦截资源

OAuth2AuthenticationProcessingFilter

  • 此过滤器与我们的token的各种操作息息相关,不清楚的可以参考别人的博客进行了解https://blog.csdn.net/u013815546/article/details/77046453
  • 下面是此过滤器的过滤方法,从中可以知道当授权失败抛出异常的时候将会被catch,并且通过authenticationEntryPoint.commence()调用端点异常处理器,这个被调用的异常处理器就是我们要重写的类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
ServletException {

final boolean debug = logger.isDebugEnabled();
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;

try {

Authentication authentication = tokenExtractor.extract(request);

...

catch (OAuth2Exception failed) {
SecurityContextHolder.clearContext();

if (debug) {
logger.debug("Authentication request failed: " + failed);
}
eventPublisher.publishAuthenticationFailure(new BadCredentialsException(failed.getMessage(), failed),
new PreAuthenticatedAuthenticationToken("access-token", "N/A"));

authenticationEntryPoint.commence(request, response,
new InsufficientAuthenticationException(failed.getMessage(), failed));

return;
}

chain.doFilter(request, response);
}

分析默认端点异常处理器

从过滤器源码中我们可以看到此异常处理器是有默认实现类的

1
2
3
4
5
6
7
8
9
public class OAuth2AuthenticationProcessingFilter implements Filter, InitializingBean {

private final static Log logger = LogFactory.getLog(OAuth2AuthenticationProcessingFilter.class);

private AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();

...

}

通过查看此默认处理器,我们可以发现里面主要调用了doHandle的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public class OAuth2AuthenticationEntryPoint extends AbstractOAuth2SecurityExceptionHandler implements
AuthenticationEntryPoint {

...

public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
doHandle(request, response, authException);
}

...

}

我们再次查看doHandle的具体内容可以得出此过滤器的主要功能有3个:

  1. 解析异常类型
  2. 扩展respone的一些属性和内容
  3. respone 刷新缓存直接返回
1
2
3
4
5
6
7
8
9
10
11
protected final void doHandle(HttpServletRequest request, HttpServletResponse response, Exception authException)
throws IOException, ServletException {
try {
ResponseEntity<?> result = exceptionTranslator.translate(authException);
result = enhanceResponse(result, authException);
exceptionRenderer.handleHttpEntityResponse(result, new ServletWebRequest(request, response));
response.flushBuffer();
}

...
}

重写异常处理器

对默认异常处理器的分析,我们可以得出如果是我们需要的异常(401异常)则用我们自定义的方法进行处理,如果是其他异常则让原来的异常处理器处理即可,大致思路如下:

  1. 通过exceptionTranslator.translate(authException)解析异常,判断异常类型(status)
  2. 如果不是401异常,则直接调用默认异常处理器的处理方法即可
  3. 如果是401异常则向授权服务器发起token刷新的请求
  4. 如果token刷新成功,则通过request.getRequestDispatcher(request.getRequestURI()).forward(request,response);再次请求资源
  5. 如果token刷新失败,要么跳转到登陆页面(web的话也可以通过response.sendirect跳转到登陆页面),要么返回错误信息(json)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

public class LLGAuthenticationEntryPoint extends OAuth2AuthenticationEntryPoint {

@Autowired
private OAuth2ClientProperties oAuth2ClientProperties;
@Autowired
private BaseOAuth2ProtectedResourceDetails baseOAuth2ProtectedResourceDetails;
private WebResponseExceptionTranslator<?> exceptionTranslator = new DefaultWebResponseExceptionTranslator();
@Autowired
RestTemplate restTemplate;

@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
try {
//解析异常,如果是401则处理
ResponseEntity<?> result = exceptionTranslator.translate(authException);
if (result.getStatusCode() == HttpStatus.UNAUTHORIZED) {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("client_id", oAuth2ClientProperties.getClientId());
formData.add("client_secret", oAuth2ClientProperties.getClientSecret());
formData.add("grant_type", "refresh_token");
Cookie[] cookie=request.getCookies();
for(Cookie coo:cookie){
if(coo.getName().equals("refresh_token")){
formData.add("refresh_token", coo.getValue());
}
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
Map map = restTemplate.exchange(baseOAuth2ProtectedResourceDetails.getAccessTokenUri(), HttpMethod.POST,
new HttpEntity<MultiValueMap<String, String>>(formData, headers), Map.class).getBody();
//如果刷新异常,则坐进一步处理
if(map.get("error")!=null){
// 返回指定格式的错误信息
response.setStatus(401);
response.setHeader("Content-Type", "application/json;charset=utf-8");
response.getWriter().print("{\"code\":1,\"message\":\""+map.get("error_description")+"\"}");
response.getWriter().flush();
//如果是网页,跳转到登陆页面
//response.sendRedirect("login");
}else{
//如果刷新成功则存储cookie并且跳转到原来需要访问的页面
for(Object key:map.keySet()){
response.addCookie(new Cookie(key.toString(),map.get(key).toString()));
}
request.getRequestDispatcher(request.getRequestURI()).forward(request,response);
}
}else{
//如果不是401异常,则以默认的方法继续处理其他异常
super.commence(request,response,authException);
}
} catch (Exception e) {
e.printStackTrace();
}

}

}

将处理器设置到过滤器上

由于spring security遵循适配器的设计模式,所以我们可以直接从配置类上配置此处理器

1
2
3
4
5
6
7
8
9
10
11
12
13
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public abstract class ResServerConfig extends ResourceServerConfigurerAdapter {

...

@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
super.configure(resources);

resources.authenticationEntryPoint(new LLGAuthenticationEntryPoint());

}

评论