一、简介
Spring Security 中异常主要分为两大类:
1、AuthenticationException: 认证异常
2、AccessDeniedException: 授权异常
AuthenticationEntryPoint 该类用来统一处理
AuthenticationException
异常AccessDeniedHandler 该类用来统一处理
AccessDeniedException
异常我们只要实现并配置这两个异常处理类即可实现对 Spring Security 认证授权相关的异常进行统一的自定义处理。
二、AuthenticationException 认证异常
异常介绍:
org.springframework.security.authentication.AccountStatusException 账号相关异常,抽象类,下面有三个实现类
org.springframework.security.authentication.AccountExpiredException 账号过期异常
org.springframework.security.authentication.CredentialsExpiredException 凭证过期(密码过期)
org.springframework.security.authentication.DisabledException 账号禁用异常
org.springframework.security.authentication.LockedException 账号已锁定异常
2.1 认证异常常用处理
@Bean
public LoginFilter loginVerifyImgFilter() throws Exception {
LoginFilter filter = new LoginFilter();
filter.setUsernameParameter("loginId");
filter.setPasswordParameter("pwd");
filter.setFilterProcessesUrl("/login.do");
// 成功的响应
filter.setAuthenticationSuccessHandler((req,resp,auth) -> {
Map<String,Object> resMap = new HashMap<>();
resMap.put("code","0000");
resMap.put("msg","登录成功!");
resMap.put("data",auth);
WebRespUtils.writeJson(resp,resMap);
});
//登录失败的处理
filter.setAuthenticationFailureHandler((req,resp,ex) -> {
Map<String,Object> resMap = new HashMap<>();
String errMsg = "登录失败";
resMap.put("code","5001");
if (ex instanceof LockedException) {
errMsg = "账户被锁定,请联系管理员!";
} else if (ex instanceof CredentialsExpiredException) {
errMsg = "密码过期,请联系管理员!";
} else if (ex instanceof AccountExpiredException) {
errMsg = "账户过期,请联系管理员!";
} else if (ex instanceof DisabledException) {
errMsg = "账户被禁用,请联系管理员!";
} else if (ex instanceof BadCredentialsException) {
errMsg = "用户名或者密码输入错误,请重新输入!";
}
resMap.put("msg",errMsg);
WebRespUtils.writeJson(resp,resMap);
});
// 指定自己的authenticationmanager
filter.setAuthenticationManager(authenticationManagerBean());
return filter;
}
三、AccessDeniedException 授权异常
授权异常 AccessDeniedException,授权异常的实现类比较少,因为授权失败的可能原因比较少,主要是在用户在访问受保护资源时被拒绝而抛出的异常
3.1 401 未授权状态
HTTP 401 错误 - 未授权(Unauthorized) 一般来说该错误消息表明您首先需要登录(输入有效的用户名和密码)。如果你刚刚输入这些信息,立刻就看到一个
401
错误,就意味着,无论出于何种原因您的用户名和密码其中之一或两者都无效(输入有误,用户名暂时停用,账户被锁定,凭证失效等) 。总之就是认证失败了。其实正好对应我们上面的AuthenticationException
。3.2 403 被拒绝状态
HTTP 403 错误 - 被禁止(Forbidden) 出现该错误表明您在访问受限资源时没有得到许可。服务器理解了本次请求但是拒绝执行该任务,该请求不该重发给服务器。并且服务器想让客户端知道为什么没有权限访问特定的资源,服务器应该在返回的信息中描述拒绝的理由。一般实践中我们会比较模糊的表明原因。该错误对应了我们上面的
AccessDeniedException
。
四、代码处理异常
自定义认证异常处理类和授权异常处理类:
/*
* 自定义认证异常处理
*/
@Component
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
Map<String,Object> resMap = new HashMap<>();
String errMsg = authException.getMessage();
resMap.put("code","5001");
resMap.put("msg",errMsg);
WebRespUtils.writeJson(response,resMap);
}
}
/*
* 自定义授权异常处理
*/
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setStatus(403);
Map<String,Object> resMap = new HashMap<>();
String errMsg = authException.getMessage();
resMap.put("code","403");
resMap.put("msg",errMsg);
WebRespUtils.writeJson(response,resMap);
}
}
4.2 SecurityConfig 中进行配置
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
...
...
.and()
.exceptionHandling()
.authenticationEntryPoint(myAuthenticationEntryPoint)
.accessDeniedHandler(myAccessDeniedHandler)
.and()
...
...
}
}