springboot+security自定义认证异常和授权异常

1、Spring Security异常
Spring Security异常主要分为两大类:

  • 认证异常:AuthenticationException,这个是所有认证异常的父类
    BadCredentialsException登录凭证异常、UsernameNotFoundException用户名不存在异常、LockedException账户被锁定异常等
  • 权限异常:AccessDeniedException,这个是所有权限异常的父类;
    CsrfException Csrf令牌异常等

2、自定义认证异常和授权异常
Spring security中一般都会在自定义配置类( WebSecurityConfigurerAdapter )中使用HttpSecurity 提供的 exceptionHandling() 方法用来提供异常处理。该方法构造出 ExceptionHandlingConfigurer 异常处理配置类。该配置类提供了两个实用接口:

  • AuthenticationEntryPoint:该类用来统一处理 AuthenticationException 异常;
  • AccessDeniedHandler:该类用来统一处理 AccessDeniedException 异常;

我们只要实现并配置这两个异常处理类即可实现对 Spring Security 认证和授权相关的异常进行统一的自定义处理。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and().formLogin()
                //开启异常处理
                .and().exceptionHandling()
                //处理认证异常
                .authenticationEntryPoint((request,response,e)->{
                    if(e instanceof LockedException){
                        //e是走的父类AuthenticationException,针对指定子类异常可以自定义一些逻辑
                    }
                    response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    response.getWriter().write("没有认证");
                })
                //处理授权异常
                .accessDeniedHandler((request,response,e)->{
                    response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
                    response.setStatus(HttpStatus.FORBIDDEN.value());
                    response.getWriter().write("授权异常");
                })
                .and().csrf().disable();
    }
}

3、自定义全局异常
如果是springboot+security项目,并且定义了全局异常,那上面的授权异常AccessDeniedException及子类和认证异常AuthenticationException及子类都会优先被全局异常执行,导致security配置的异常处理不起作用,主要原因是执行先后的问题,spring请求中各组件执行顺序如下:Controller》Aspect》ControllerAdvice》Interceptor》Filter。
可见,当发生授权异常AccessDeniedException及子类和认证异常AuthenticationException及子类都会优先被全局异常ControllerAdvice处理,所以如果还是想让security自己处理,我们在全局异常中捕获到上述异常,直接抛出就行,代码如下

@RestControllerAdvice
public class GlobalExceptionHandler {
 
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
    //security的授权异常(AccessDeniedException及子类)抛出交由security AuthenticationEntryPoint 处理
    @ExceptionHandler(AccessDeniedException.class)
    public void accessDeniedException(AccessDeniedException e) throws AccessDeniedException {
        throw e;
    }
 
    //security的认证异常(AuthenticationException及子类)抛出由security AccessDeniedHandler 处理
    @ExceptionHandler(AuthenticationException.class)
    public void authenticationException(AuthenticationException e) throws AuthenticationException {
        throw e;
    }
 
    //未知异常
    @ExceptionHandler(Exception.class)
    public Result otherException(Exception e) {
        e.printStackTrace();
        logger.error("系统异常 全局拦截异常信息:{}",e.getMessage());
        return Result.error(e.getMessage());
    }
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值