spring security 中的异常

Source

一、简介

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()
                ...
                ...
    }
}