• 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抛出异常, 以便返回友好的提示信息。有什么解决办法么?

  • 相关阅读:
    安装 Docker Machine
    volume 生命周期管理
    data-packed volume container
    用 volume container 共享数据
    如何共享数据?- 每天5分钟玩转 Docker 容器技术(41)
    docker managed volume
    Data Volume 之 bind mount
    Docker 的两类存储资源
    外部世界如何访问容器?
    容器如何访问外部世界?- 每天5分钟玩转 Docker 容器技术(36)
  • 原文地址:https://www.cnblogs.com/itrena/p/9025275.html
Copyright © 2020-2023  润新知