首先抛出自定义异常这个思路是没啥问题的,至少比抛出UsernameNotFoundException来的自由些,因为在hideUserNotFoundExceptions属性默认为true的情况下,UsernameNotFoundException会被转换成BadCredentialsException,同时连异常信息都会被写成固定的Bad credentials了,部分源码参考如下:
- 首先我们要先定义一个自定义异常类,参考如下:
/**
1. @Author:jiejie
2. @Desc: 自定义业务异常
3. @Date: 2021/3/16 11:35
4. @Version 1.0
*/
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
protected final String message;
public BusinessException(String message) {
this.message = message;
}
public BusinessException(String message, Throwable e) {
super(message, e);
this.message = message;
}
@Override
public String getMessage() {
return message;
}
}
- 此时碰到什么手机号已注册等等的业务异常,都使用该异常来处理,但是会发现,还是没法抛出我们想要的code和message。
- 自定义异常了,那我们此时就应该自定义一个全局异常处理器类,让它捕获到BusinessException,然后再封装信息做具体的返回,参考如下:
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @Author: jiejie
* @Date: 2021/4/13 下午2:11
* @Desc: 全局处理抛出的异常
* @Version 1.0
*/
@ControllerAdvice
public class Oauth2ExceptionHandler {
/**
* 业务异常
*
* @param e
* @return
*/
@ExceptionHandler(BusinessException.class)
@ResponseBody
public R handlerBusinessException(BusinessException e) {
return R.failed(BizCodeEnume.BUSSINESS_EXCEPTION, e.getMessage());
}
@ResponseBody
@ExceptionHandler(value = OAuth2Exception.class)
public R handleOauth2(OAuth2Exception e) {
return R.failed(e.getMessage());
}
}
- 继续验证,发现即使抛出的是BusinessException异常,但是全局异常处理器竟然还是没捕获到,导致返回的结果还是不符合要求,此时猜想spring security捕获UsernameNotFoundException异常再转化成BadCredentialsException异常的操作,猜测异常可能是被转化了,此时只能去跟踪源码,慢慢找,最终发现,有个大的处理逻辑,就是如果匹配不到具体的异常,就会把此时的Exception转化成InternalAuthenticationServiceException异常再抛出,具体源码如下:
- 此时的处理思路就很清晰了,在全局异常处理器中马上再加上几个要捕获处理的异常即可,修改后整体如下:
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @Author: jiejie
* @Date: 2021/4/13 下午2:11
* @Desc: 全局处理抛出的异常
* @Version 1.0
*/
@ControllerAdvice
public class Oauth2ExceptionHandler {
/**
* 业务异常
*
* @param e
* @return
*/
@ExceptionHandler(BusinessException.class)
@ResponseBody
public R handlerBusinessException(BusinessException e) {
return R.failed(BizCodeEnume.BUSSINESS_EXCEPTION, e.getMessage());
}
/**
* 用户名和密码错误
*
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(InvalidGrantException.class)
public R handleInvalidGrantException(InvalidGrantException e) {
return R.failed(BizCodeEnume.BUSSINESS_EXCEPTION, e.getMessage());
}
/**
* 账户异常(禁用、锁定、过期)
*
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler({InternalAuthenticationServiceException.class})
public R handleInternalAuthenticationServiceException(InternalAuthenticationServiceException e) {
return R.failed(BizCodeEnume.BUSSINESS_EXCEPTION, e.getMessage());
}
@ResponseBody
@ExceptionHandler(value = OAuth2Exception.class)
public R handleOauth2(OAuth2Exception e) {
return R.failed(e.getMessage());
}
}
再次测试,发现返回结果符合需求了,如下: