优化资源服务器拦截与Spring Security拦截优先级问题,资源服务拦截器优先级高于Spring Security,限制资源服务器拦截作用范围

This commit is contained in:
zhuyijun 2022-09-18 23:50:30 +08:00
parent e8dbdd18e2
commit 858dbd3abf
8 changed files with 168 additions and 21 deletions

View File

@ -0,0 +1,33 @@
package cn.zyjblogs.starter.oauth.handler;
import cn.zyjblogs.starter.common.entity.response.HttpCode;
import cn.zyjblogs.starter.common.entity.response.ResponseResult;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author zhuyijun
*/
public class ResourceAccessDeniedHandler implements AccessDeniedHandler {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final Logger log = LoggerFactory.getLogger(ResourceAccessDeniedHandler.class);
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
log.error("禁止访问 {}", e.getMessage());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
OBJECT_MAPPER.writeValue(response.getOutputStream(),
ResponseResult.error(HttpCode.FORBIDDEN, "无权访问该资源"));
}
}

View File

@ -0,0 +1,32 @@
package cn.zyjblogs.starter.oauth.handler;
import cn.zyjblogs.starter.common.entity.response.HttpCode;
import cn.zyjblogs.starter.common.entity.response.ResponseResult;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author zhuyijun
*/
public class ResourceAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final Logger log = LoggerFactory.getLogger(ResourceAuthenticationEntryPoint.class);
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
log.error("认证失败 {}", e.getMessage());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
OBJECT_MAPPER.writeValue(response.getOutputStream(),
ResponseResult.error(HttpCode.UNAUTHORIZED, "认证失败,token无效!"));
}
}

View File

@ -1,5 +1,7 @@
package cn.zyjblogs.starter.oauth.resource;
import cn.zyjblogs.starter.oauth.handler.ResourceAccessDeniedHandler;
import cn.zyjblogs.starter.oauth.handler.ResourceAuthenticationEntryPoint;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
@ -30,7 +32,9 @@ public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
resources.resourceId(resourceId)
// 验证令牌的服务
.tokenStore(tokenStore)
.stateless(true);
.stateless(true)
.accessDeniedHandler(new ResourceAccessDeniedHandler())
.authenticationEntryPoint(new ResourceAuthenticationEntryPoint());
}
@Override
@ -42,7 +46,8 @@ public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
.anyRequest()
.authenticated()
.and()
.csrf().disable();
.csrf().disable()
.httpBasic();
}
}

View File

@ -0,0 +1,33 @@
package cn.zyjblogs.oauth.config.handler;
import cn.zyjblogs.starter.common.entity.response.HttpCode;
import cn.zyjblogs.starter.common.entity.response.ResponseResult;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author zhuyijun
*/
public class ResourceAccessDeniedHandler implements AccessDeniedHandler {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final Logger log = LoggerFactory.getLogger(ResourceAccessDeniedHandler.class);
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
log.error("禁止访问 {}", e.getMessage());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
OBJECT_MAPPER.writeValue(response.getOutputStream(),
ResponseResult.error(HttpCode.FORBIDDEN, "无权访问Oauth资源"));
}
}

View File

@ -0,0 +1,32 @@
package cn.zyjblogs.oauth.config.handler;
import cn.zyjblogs.starter.common.entity.response.HttpCode;
import cn.zyjblogs.starter.common.entity.response.ResponseResult;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author zhuyijun
*/
public class ResourceAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final Logger log = LoggerFactory.getLogger(ResourceAuthenticationEntryPoint.class);
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
log.error("认证失败 {}", e.getMessage());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
OBJECT_MAPPER.writeValue(response.getOutputStream(),
ResponseResult.error(HttpCode.UNAUTHORIZED, "认证失败!"));
}
}

View File

@ -1,12 +1,12 @@
package cn.zyjblogs.oauth.config.security;
import cn.zyjblogs.oauth.config.handler.ResourceAccessDeniedHandler;
import cn.zyjblogs.oauth.config.handler.ResourceAuthenticationEntryPoint;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
@ -16,7 +16,7 @@ import org.springframework.security.oauth2.provider.token.TokenStore;
@EnableResourceServer
@RequiredArgsConstructor
@RefreshScope
@Order(100)
//@Order(50)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Value("${spring.application.name}")
private String resourceId;
@ -27,22 +27,35 @@ public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
resources.resourceId(resourceId)
// 验证令牌的服务
.tokenStore(tokenStore)
.stateless(true);
.stateless(true)
.accessDeniedHandler(new ResourceAccessDeniedHandler())
.authenticationEntryPoint(new ResourceAuthenticationEntryPoint());
}
/**
* 资源服务器拦截优先级高于Spring Scurity限制资源服务器作用范围
*
* @param http
* @return void
* @author zhuyijun
* @date 2022/9/18 下午10:52
*/
@Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
http
.csrf()
.disable()
//限制资源服务器作用范围为 "/user/**", "/demo/**"
.requestMatchers().antMatchers("/user/**", "/demo/**").and()
.formLogin().and()
.authorizeRequests()
.antMatchers("/user/login", "/login", "/user/refresh/token")
.permitAll()
.antMatchers("/webjars/**", "/swagger-ui.html/**", "/swagger-resources/**", "/v2/api-docs/**")
.permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable();
.antMatchers("/login", "/oauth/**", "/user/login", "/user/refresh/token").permitAll()
//以下请求必须认证通过
.anyRequest()
.authenticated().and()
.httpBasic();
}
}

View File

@ -4,7 +4,6 @@ import cn.zyjblogs.oauth.server.user.service.impl.OauthUserDetailsServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@ -16,7 +15,7 @@ import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@Order(1)
//@Order(1)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
private final OauthUserDetailsServiceImpl userDetailsService;
@ -55,12 +54,11 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
http.csrf().disable();
//使HttpSecurity接收以"/login/","/oauth/"开头请求, 配置HttpSecurity不阻止swagger页面
http.authorizeRequests()
.antMatchers("/webjars/**", "/swagger-ui.html/**", "/swagger-resources/**", "/v2/api-docs/**")
.permitAll()
.antMatchers("/login", "/oauth/**", "/user/logout", "/user/login", "/user/refresh/token").permitAll()
// .antMatchers("/webjars/**", "/swagger-ui.html/**", "/swagger-resources/**", "/v2/api-docs/**")
// .permitAll()
// .antMatchers("/user/logout", "/login", "/oauth/**", "/user/login", "/user/refresh/token").permitAll()
//以下请求必须认证通过
.anyRequest()
.authenticated()
.anyRequest().authenticated()
.and()
//允许表单登录
.formLogin()

View File

@ -27,6 +27,7 @@ spring:
logging:
config: classpath:logback-spring.xml
#security:
# oauth2:
# client: