Spring boot 前后台分离项目 怎么处理spring security 抛出的异常

Posted zhengguangaa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring boot 前后台分离项目 怎么处理spring security 抛出的异常相关的知识,希望对你有一定的参考价值。

最近在开发一个项目 前后台分离的 使用 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 抛出的异常的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot 前后台分离项目 怎么处理spring security 抛出的异常

Spring boot 前后台分离项目 怎么处理spring security 抛出的异常

Spring boot 前后台分离项目 怎么处理spring security 抛出的异常

Spring boot 前后台分离项目 怎么处理spring security 抛出的异常

Spring Boot+Vue 前后端分离项目架构

spring boot+vue前后端项目的分离(我的第一个前后端分离项目)