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

原文地址:https://www.cnblogs.com/zhengmantoua/p/9025651.html

时间: 2024-10-06 02:44:03

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

Maven 搭建spring boot多模块项目

Maven 搭建spring boot多模块项目 备注:所有项目都在idea中创建 1.idea创建maven项目 1-1: 删除src,target目录,只保留pom.xml 1-2: 根目录pom.xml可被子模块继承,因此项目只是demo,未考虑太多性能问题,所以将诸多依赖 都写在根级`pom.xml`,子模块只需继承就可以使用. 1-3: 根级pom.xml文件在附录1 1-4: 依赖模块 mybatis spring-boot相关模块 2.创建子模块(module) 2-1: file

从零一起学Spring Boot之LayIM项目长成记(一) 初见 Spring Boot

项目背景 之前写过LayIM的.NET版后端实现,后来又写过一版Java的.当时用的是servlet,websocket和jdbc.虽然时间过去很久了,但是仍有些同学在关注.偶然间我听说了SpringBoot这么个东东,据说是省去了很多繁杂的配置.可以傻瓜式的创建项目,轻轻松松做出一个网站来,那么出于我对LayIM的情有独钟,于是乎想借用它来帮助我学习SpringBoot,并且全程记录,省的以后再走弯路和掌握解决问题的方法.(当然,我也是新手,我的解决方法就是百度,stackovreflow等网

从零一起学Spring Boot之LayIM项目长成记(五)websocket

前言 距离上一篇已经比较久的时间了,项目也是开了个头.并且,由于网上的关于Spring Boot的websocket讲解也比较多.于是我采用了另外的一个通讯框架 t-io 来实现LayIM中的通讯功能.本篇会着重介绍我在研究与开发过程中踩过的坑和比较花费的时间的部分. WebSocket 在研究 t-io 的时候,我已经写过关于t-io框架的一些简单例子分析以及框架中关于 websocket 中的编解码代码分析等,有兴趣的同学可以先看一下.因为 在LayIM项目中我会是用到 Showcase D

spring boot+mybatis+quartz项目的搭建完整版

1. 利用spring boot提供的工具(http://start.spring.io/)自动生成一个标准的spring boot项目架构 2. 因为这里我们是搭建spring boot+mybatis+quartz架构,故在pom.xml文件中配置相关依赖 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boo

Spring Boot 多模块项目创建与配置 (一) (转)

最近在负责的是一个比较复杂项目,模块很多,代码中的二级模块就有9个,部分二级模块下面还分了多个模块.代码中的多模块是用maven管理的,每个模块都使用spring boot框架.之前有零零散散学过一些maven多模块配置的知识,但没自己从头到尾创建和配置过,也快忘得差不多了.这次正好对照着这个项目,动手实践一下,下面我们就开始吧. maven多模块项目通常由一个父模块和若干个子模块构成,每个模块都对应着一个pom.xml.它们之间通过继承和聚合(也称作多模块)相互关联.多模块适用于一些比较大的项

Github 上 Star 最多的个人 Spring Boot 开源学习项目

2016年,在一次技术调研的过程中认识到了 Spring Boot ,试用之后便一发不可收拾的爱上它.为了防止学习之后忘记,就在网上连载了 Spring Boot 系列文章,没想到这一开始便与 Spring Boot 深度结缘. 近三年的时间写了一百多篇关于 Spring Boot 的文章(包含两个课程),在写文章的过程中将文中的示例项目托管在 Github 上面,随着学习 Spring Boot 的朋友越来越多,在 Github 上面的关注(Star)人数也越来越多,到现在已经高达 8300

Spring Boot -05- 多模块结构项目构建与测试(详细图文教程)IDEA 版

Spring Boot -05- 多模块结构项目构建与测试(详细图文教程)IDEA 版 百度很多博客都不详细,弄了半天才把 Spring Boot 多模块项目构建开发整的差不多,特地重新创建配置,记录一下,也分享给有需要的人 本篇也会非常详细的介绍涉及的基础知识点,更多都写在注释上了 先放成功截图: (1)项目结构: (2)启动: (3)测试主子模块: (4)测试子模块依赖: 第一步:创建父模块,子模块 (1)打开创建项目窗口,点击 Create New Project (2)填写 (3)填写

【Spring Boot】利用 Spring Boot Admin 进行项目监控管理

利用 Spring Boot Admin 进行项目监控管理 一.Spring Boot Admin 是什么 Spring Boot Admin (SBA) 是一个社区开源项目,用于管理和监视 Spring Boot 应用程序.应用程序通过 http 的方式注册到 Spring Boot 管理客户端,或者通过 Spring Cloud 的服务发现机制,然后针对 actuator 接口将数据通过 Vue.js 进行可视化管理. 对于我们来说,我们可以通过 Spring Boot Admin 浏览所有

spring boot 系列之六:@Conditional和spring boot的自动配置

我们知道,spring boot自动配置功能可以根据不同情况来决定spring配置应该用哪个,不应该用哪个,举个例子: Spring的JdbcTemplate是不是在Classpath里面?如果是,并且DataSource也存在,就自动配置一个JdbcTemplate的Bean Thymeleaf是不是在Classpath里面?如果是,则自动配置Thymeleaf的模板解析器.视图解析器.模板引擎 那个这个是怎么实现的呢?原因就在于它利用了Spring的条件化配置,条件化配置允许配置存在于应用中