文末有本篇文章的项目源码可供下载学习。
在实际的项目开发过程中,我们对于认证失败或者授权失败需要像接口一样返回相同结构的json数据,这样可以让前端对响应进行统一的处理。要实现这个功能我们需要知道SpringSecurity的异常处理机制。
在SpringSecurity中,如果发生了认证或者授权失败的情况下,产生的异常都会被ExceptionTranslationFilter捕获到,在ExceptionTranslationFilter中会去判断是认证失败还是授权失败。
如果发生了认证异常,会抛出AuthenticationException然后调用AuthenticationEntryPoint对象的方法去进行异常处理。
如果发生了授权异常,会抛出AccessDeniedException然后调用AccessDeniedHandler对象的方法去进行异常处理。
所以我们就需要实现AuthenticationException和AccessDeniedException这两个接口,将这两个接口的实现类对象配置给SpringSecurity即可。
0.配置思路
- 在本项目案例的基础上进行开发
- 自定义认证失败处理器AuthenticationEntryPointImpl.java和自定义授权失败处理器AccessDeniedHandlerImpl.java
- 将自定义认证失败处理器和自定义授权失败处理器配置到SpringSecurity的配置文件中。
- 进行相关测试。
1.自定义认证失败处理器AuthenticationEntryPointImpl.java
/**
* 认证失败处理器
*/
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
CustomerResult result = new CustomerResult().code(HttpStatus.UNAUTHORIZED.toString()).msg("用户认证失败");
String jsonString = JSON.toJSONString(result);
// 处理异常
WebUtil.renderString(response, jsonString);
}
}
2. 自定义授权失败处理器AccessDeniedHandlerImpl.java
/**
* 授权失败处理器
*/
@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
CustomerResult result = new CustomerResult().code(HttpStatus.FORBIDDEN.toString()).msg("访问权限不足");
String jsonString = JSON.toJSONString(result);
// 处理异常
WebUtil.renderString(response, jsonString);
}
}
3.编辑SpringSecurity的配置文件
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticateFilter jwtAuthenticateFilter;
@Autowired
private AuthenticationEntryPointImpl authenticationEntryPoint;
@Autowired
private AccessDeniedHandlerImpl accessDeniedHandler;
/**
* 用户密码加密处理
* @return
*/
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 关闭csrf
.csrf().disable()
// 不通过session获取SecurityContext
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
// 放行登录接口,允许匿名访问
.antMatchers("/security/login").anonymous()
// 登录不登录的都可以访问,放行
// .antMatchers("/hello").permitAll()
// 除上面外的所有请求全部需要认证授权
.anyRequest().authenticated();
// 配置认证jwt过滤器
http.addFilterBefore(jwtAuthenticateFilter, UsernamePasswordAuthenticationFilter.class);
// 配置异常处理器
http.exceptionHandling()
// 认证失败处理器
.authenticationEntryPoint(authenticationEntryPoint)
// 授权失败处理器
.accessDeniedHandler(accessDeniedHandler);
}
/**
* 认证管理器
* @return
* @throws Exception
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
4.相关测试
4.1先将在SpringSecurity中关于自定义认证失败处理器和自定义授权失败处理器的配置注释掉
4.2将在SpringSecurity中关于自定义认证失败处理器取消注释
4.3 我们在注释掉权限认证处理器的基础上,访问一下后台的权限方法,将权限字符串修改为错误的权限字符串
4.3.1正确登录,获取token信息
4.3.2尝试访问
4.4将在SpringSecurity的自定义授权失败处理器取消注释,再次访问。