How to deal with exceptions thrown by spring security in Spring boot front and back separated projects

Recently, I used spring boot + spring security + jwt to separate the front and back of a project to realize user login permission control and other operations. But when the user logs in, how to deal with the exception thrown by spring security? Using @RestControllerAdvice and @ExceptionHandler cannot handle exceptions thrown by Spring Security, such as UsernameNotFoundException, etc. I want to return prompt information to the front end friendly, such as, the username does not exist. Paste my code:

JWT authentication class: Override 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 Accept and parse user credentials
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException {
        try {
            AuthEntity creds = new ObjectMapper()
                    .readValue(req.getInputStream(), AuthEntity.class);

            // verification code
            if (appConfig.getCaptchaEnabled()) { //If the verification code login verification function is enabled
                if (StringUtils.isBlank(creds.getCaptcha())) {
                    logger.error("Verification code is empty");
                    throw new WelendException(StatusCode.CAPTCHA_EMPTY);
                }
                if (!redisService.exists(appConfig.getCaptchaKey())) {
                    logger.error("Verification code has expired");
                    throw new WelendException(StatusCode.CAPTCHA_OVERDUE);
                }
                String captcha = (String) redisService.get(appConfig.getCaptchaKey());
                if (!creds.getCaptcha().equals(captcha)) {
                    logger.error("The verification code is incorrect");
                    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);
        }

    }
}

Verify username and password:

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 {
        // Get authenticated username & password
        String name = authentication.getName();
        String password = authentication.getCredentials().toString();
        // authentication logic
        JWTUserDetails userDetails = userDetailsService.loadUserByUsername(name);
        if (null != userDetails) {
            Boolean verifyPwd = bCryptPasswordEncoder.matches(password,userDetails.getLoginPwd());
            if (verifyPwd) {
                // Generate a token This token is stored in: userDetails, password, authorities (authority list)
                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");
        }
    }

    /**
     * Is it possible to provide authentication service of input type
     * @param authentication
     * @return
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }

}

global exception handling

@RestControllerAdvice
public class GlobalExceptionHandler {
    private Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * @param request
     * @param exception
     * @return
     * @throws Exception
     * @// TODO: 2018/4/25 parameter failed validation exception
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Object MethodArgumentNotValidHandler(HttpServletRequest request, MethodArgumentNotValidException exception) throws Exception {
        //Re-encapsulate the error message that needs to be returned as needed
        //List<StatusCode> invalidArguments = new ArrayList<>();
        //Parse the original error information, return it after encapsulation, here returns the illegal field name, original value, error information
        ResultObject resultMsg = ResultObject.dataMsg(exception.getBindingResult().getFieldError().getDefaultMessage(), StatusCode.VARIABLE_ERROR);
        return resultMsg;
    }

    /**
     * @param request
     * @param exception
     * @return
     * @throws Exception
     * @// TODO: 2018/4/25 Unable to parse parameter exception
     */
    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    public Object HttpMessageNotReadableHandler(HttpServletRequest request, HttpMessageNotReadableException exception) throws Exception {
        logger.info(exception.getMessage());
        ResultObject resultMsg = ResultObject.dataMsg("The parameter cannot be parsed normally", StatusCode.VARIABLE_ERROR);
        return resultMsg;
    }

    /**
     * @param exception
     * @return
     * @throws Exception
     * @// TODO: 2018/4/25 Handle token expiration exception
     */
    @ExceptionHandler(value = ExpiredJwtException.class)
    public Object ExpiredJwtExceptionHandler(ExpiredJwtException exception) throws Exception {
        logger.info(exception.getMessage());
        ResultObject resultMsg = ResultObject.dataMsg("Login has expired!", StatusCode.FORBIDDEN);
        return resultMsg;
    }

    /**
     * @param request
     * @param exception
     * @return
     * @throws Exception
     * @// TODO: 2018/4/25 Insufficient method access permission exception
     */
    @ExceptionHandler(value = AccessDeniedException.class)
    public Object AccessDeniedExceptionHandler(AccessDeniedException exception) throws Exception {
        logger.info(exception.getMessage());
        ResultObject resultMsg = ResultObject.dataMsg("Insufficient permission!", StatusCode.FORBIDDEN);
        return resultMsg;
    }

    @ExceptionHandler(value = NoHandlerFoundException.class)
    public Object NoHandlerFoundExceptionHandler(NoHandlerFoundException exception) throws Exception {
        logger.info(exception.getMessage());
        return ResultObject.dataMsg("Link does not exist", StatusCode.NOT_FOUND);
    }
    /**
     * Handle custom exceptions
     */
    @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);
    }
}

Wrong username entered when logging in

The console prints the information directly, and it is not processed by ExceptionHandler.

As shown above, I want to handle exceptions thrown by spring security in the global exception class in order to return friendly prompt information. Is there any solution?

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325974761&siteId=291194637