Spring boot 前後臺分離項目 怎麽處理spring security 拋出的異常
阿新 • • 發佈:2018-05-11
輸入 etl tor login 異常 stat dup valid load
最近在開發一個項目 前後臺分離的 使用 spring boot + spring security + jwt 實現用戶登錄權限控制等操作。但是 在用戶登錄的時候,怎麽處理spring security 拋出的異常呢?使用了@RestControllerAdvice 和@ExceptionHandler 不能處理Spring Security拋出的異常,如 UsernameNotFoundException等,我想要友好的給前端返回提示信息 如,用戶名不存在之類的。 貼上我的代碼:
JWT 驗證類 : 重寫了spring security UsernamaPasswordAuthenticationFilter
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
private RedisServiceImpl redisService;
private AppConfig appConfig;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager, RedisServiceImpl redisService, AppConfig appConfig) {
this.authenticationManager = authenticationManager;
this.redisService = redisService;
this.appConfig = appConfig;
}
/**
* @param req
* @param res
* @return
* @throws AuthenticationException
* @// TODO: 2018/4/12 接受並解析用戶憑證
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException {
try {
AuthEntity creds = new ObjectMapper()
.readValue(req.getInputStream(), AuthEntity.class);
//驗證碼校驗
if (appConfig.getCaptchaEnabled()) { //如果開啟了驗證碼登錄校驗功能
if (StringUtils.isBlank(creds.getCaptcha())) {
logger.error("驗證碼為空");
throw new WelendException(StatusCode.CAPTCHA_EMPTY);
}
if (!redisService.exists(appConfig.getCaptchaKey())) {
logger.error("驗證碼已失效");
throw new WelendException(StatusCode.CAPTCHA_OVERDUE);
}
String captcha = (String) redisService.get(appConfig.getCaptchaKey());
if (!creds.getCaptcha().equals(captcha)) {
logger.error("驗證碼不正確");
throw new WelendException(StatusCode.CAPTCHA_ERROR);
}
}
return authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
creds.getUsername(),
creds.getPassword(),
new ArrayList<>())
);
} catch (IOException e) {
logger.error("Client‘s variables can‘t be parsed by com.fasterxml.jackson.core.JsonParse");
throw new WelendException(StatusCode.SERVER_ERROR);
}
}
}
驗證用戶名 密碼:
public class CustomAuthenticationProvider implements AuthenticationProvider {
private UserDetailsServiceImpl userDetailsService;
private BCryptPasswordEncoder bCryptPasswordEncoder;
public CustomAuthenticationProvider(UserDetailsServiceImpl userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 獲取認證的用戶名 & 密碼
String name = authentication.getName();
String password = authentication.getCredentials().toString();
// 認證邏輯
JWTUserDetails userDetails = userDetailsService.loadUserByUsername(name);
if (null != userDetails) {
Boolean verifyPwd = bCryptPasswordEncoder.matches(password,userDetails.getLoginPwd());
if (verifyPwd) {
// 生成令牌 這裏令牌裏面存入了:userDetails,password,authorities(權限列表)
Authentication auth = new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
return auth;
} else {
throw new BadCredentialsException("username or password wrong!");
}
} else {
throw new UsernameNotFoundException("can not find this account");
}
}
/**
* 是否可以提供輸入類型的認證服務
* @param authentication
* @return
*/
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
全局異常處理
@RestControllerAdvice
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
/**
* @param request
* @param exception
* @return
* @throws Exception
* @// TODO: 2018/4/25 參數未通過驗證異常
*/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Object MethodArgumentNotValidHandler(HttpServletRequest request, MethodArgumentNotValidException exception) throws Exception {
//按需重新封裝需要返回的錯誤信息
//List<StatusCode> invalidArguments = new ArrayList<>();
//解析原錯誤信息,封裝後返回,此處返回非法的字段名稱,原始值,錯誤信息
ResultObject resultMsg = ResultObject.dataMsg(exception.getBindingResult().getFieldError().getDefaultMessage(), StatusCode.VARIABLE_ERROR);
return resultMsg;
}
/**
* @param request
* @param exception
* @return
* @throws Exception
* @// TODO: 2018/4/25 無法解析參數異常
*/
@ExceptionHandler(value = HttpMessageNotReadableException.class)
public Object HttpMessageNotReadableHandler(HttpServletRequest request, HttpMessageNotReadableException exception) throws Exception {
logger.info(exception.getMessage());
ResultObject resultMsg = ResultObject.dataMsg("參數無法正常解析", StatusCode.VARIABLE_ERROR);
return resultMsg;
}
/**
* @param exception
* @return
* @throws Exception
* @// TODO: 2018/4/25 處理token 過期異常
*/
@ExceptionHandler(value = ExpiredJwtException.class)
public Object ExpiredJwtExceptionHandler(ExpiredJwtException exception) throws Exception {
logger.info(exception.getMessage());
ResultObject resultMsg = ResultObject.dataMsg("登錄已過期!", StatusCode.FORBIDDEN);
return resultMsg;
}
/**
* @param request
* @param exception
* @return
* @throws Exception
* @// TODO: 2018/4/25 方法訪問權限不足異常
*/
@ExceptionHandler(value = AccessDeniedException.class)
public Object AccessDeniedExceptionHandler(AccessDeniedException exception) throws Exception {
logger.info(exception.getMessage());
ResultObject resultMsg = ResultObject.dataMsg("權限不足!", StatusCode.FORBIDDEN);
return resultMsg;
}
@ExceptionHandler(value = NoHandlerFoundException.class)
public Object NoHandlerFoundExceptionHandler(NoHandlerFoundException exception) throws Exception {
logger.info(exception.getMessage());
return ResultObject.dataMsg("鏈接不存在", StatusCode.NOT_FOUND);
}
/**
* 處理自定義異常
*/
@ExceptionHandler(value = WelendException.class)
public Object WelendExceptionHandler(WelendException e) {
ResultObject r = new ResultObject();
r.setStatus(String.valueOf(e.getCode()));
r.setMessage(e.getMessage());
return r;
}
@ExceptionHandler(value = AuthenticationException.class)
public Object AuthenticationExceptionHandler(AuthenticationException e) {
return ResultObject.dataMsg(e.getLocalizedMessage(),StatusCode.FORBIDDEN);
}
@ExceptionHandler(value = DuplicateKeyException.class)
public Object DuplicateKeyExceptionHandler(DuplicateKeyException e) throws Exception {
logger.error(e.getMessage(), e);
return ResultObject.codeMsg(StatusCode.EXISTED);
}
@ExceptionHandler(value = BadCredentialsException.class)
public Object BadCredentialsExceptionHandler(BadCredentialsException e) throws Exception {
logger.error(e.getMessage(), e);
return ResultObject.codeMsg(StatusCode.AUTH_ERROR);
}
@ExceptionHandler(value = Exception.class)
public Object ExceptionHandler(Exception e) throws Exception {
logger.error(e.getMessage(), e);
return ResultObject.codeMsg(StatusCode.FAILED);
}
}
登錄時輸入錯誤的用戶名
控制臺直接打印信息了, 並沒有經過ExceptionHandler 處理。
如上所示,我想在全局異常類中 處理spring security拋出異常, 以便返回友好的提示信息。有什麽解決辦法麽?
Spring boot 前後臺分離項目 怎麽處理spring security 拋出的異常