1. 说明
SpringSecurity的实现原理是过滤器,它的执行时间比SpringMVC早,因此在执行SpringSecurity相关功能(如用户登录)时是使用不到SpringMVC的统一返回处理@ContrtollerAdvice
+ @ExceptionHandler
的组合套装的。
2. SpringSecurity 实现 @ContrtollerAdvice
增强
SpringSecurity想要实现@ControllerAdvice
需要对其认证返回 的异常做自定义处理,并引用SpringMVC的异常处理器
其思路就是在返回扩展接口中调用SpringMVC的异常解析器来解析处理,这样就衔接上了SpringMVC的扩展
示例实现如下
2.1. 引入依赖
引入SpringSecurity和SpringMVC的相关依赖
1 2 3 4 5 6 7 8
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
|
2.2. 配置异常解析器
首先是创建一个异常处理类,处理SpringSecurity的异常
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
| @Component public class SecurityAuthenticationExceptionResolverHandler implements AuthenticationEntryPoint, AuthenticationFailureHandler, AccessDeniedHandler {
private static final Logger logger = LoggerFactory.getLogger(SecurityAuthenticationExceptionResolverHandler.class);
@Autowired HandlerExceptionResolver handlerExceptionResolver;
@Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { resolver(request, response, exception); }
@Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exception) throws IOException, ServletException { resolver(request, response, exception); }
@Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { resolver(request, response, exception); }
private void resolver(HttpServletRequest request, HttpServletResponse response, Exception exception) { ModelAndView modelAndView = handlerExceptionResolver.resolveException(request, response, null, exception); if (modelAndView == null) { logger.warn("安全异常返回无处理解析器,按照默认返回"); response.setContentType("application/json;charset=utf-8"); try { PrintWriter out = response.getWriter(); out.write("Security 安全框架返回异常,且没有配置返回解析,异常信息:" + exception.getMessage()); out.flush(); out.close(); } catch (IOException e) { throw new AuthenticationServiceException("SecurityExceptionResolverHandler 解析返回异常", e); } } } }
|
然后再SecurityConfig的配置类中配置异常的处理,需配置三处
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Configuration @EnableConfigurationProperties({SecurityLoginProperties.class}) public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired SecurityAuthenticationExceptionResolverHandler exceptionResolverHandler; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .failureHandler(exceptionResolverHandler).and() .exceptionHandling() .accessDeniedHandler(exceptionResolverHandler) .authenticationEntryPoint(exceptionResolverHandler) .and() ; } }
|
配置异常增强
然后就可以像配置普通SpringMVC工程一样配置增强即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @RestControllerAdvice public class ExceptionAdviceHandler { private static final Logger logger = LoggerFactory.getLogger(ExceptionAdviceHandler.class);
@ExceptionHandler(AccessDeniedException.class) public Result accessDeniedException(Throwable t){ logger.error("访问异常:{}", t.getMessage(), t); return Result.failed(500, t.getMessage()); } @ExceptionHandler(AuthenticationException.class) public Result authenticationException(Throwable t){ logger.error("授权异常:{}", t.getMessage(), t); return Result.failed(500, t.getMessage()); } @ExceptionHandler(Throwable.class) public Result throwException(Throwable t){ logger.error("全局异常:{}", t.getMessage(), t); return Result.failed(500, t.getMessage()); }
}
|
引用