最近在开发一个项目 前后台分离的 使用 spring boot + spring security + jwt 实现用户登录权限控制等操作。但是 在用户登录的时候,怎么处理spring  security  抛出的异常呢?使用了@RestControllerAdvice 和@ExceptionHandler 不能处理Spring Security抛出的异常,如 UsernameNotFoundException等,我想要友好的给前端返回提示信息  如,用户名不存在之类的。 贴上我的代码:

JWT 验证类 : 重写了spring security UsernamaPasswordAuthenticationFilter

  1. public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
  2.  
  3. private AuthenticationManager authenticationManager;
  4.  
  5. private RedisServiceImpl redisService;
  6.  
  7. private AppConfig appConfig;
  8.  
  9. public JWTAuthenticationFilter(AuthenticationManager authenticationManager, RedisServiceImpl redisService, AppConfig appConfig) {
  10. this.authenticationManager = authenticationManager;
  11. this.redisService = redisService;
  12. this.appConfig = appConfig;
  13. }
  14.  
  15. /**
  16. * @param req
  17. * @param res
  18. * @return
  19. * @throws AuthenticationException
  20. * @// TODO: 2018/4/12 接受并解析用户凭证
  21. */
  22. @Override
  23. public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException {
  24. try {
  25. AuthEntity creds = new ObjectMapper()
  26. .readValue(req.getInputStream(), AuthEntity.class);
  27.  
  28. //验证码校验
  29. if (appConfig.getCaptchaEnabled()) { //如果开启了验证码登录校验功能
  30. if (StringUtils.isBlank(creds.getCaptcha())) {
  31. logger.error("验证码为空");
  32. throw new WelendException(StatusCode.CAPTCHA_EMPTY);
  33. }
  34. if (!redisService.exists(appConfig.getCaptchaKey())) {
  35. logger.error("验证码已失效");
  36. throw new WelendException(StatusCode.CAPTCHA_OVERDUE);
  37. }
  38. String captcha = (String) redisService.get(appConfig.getCaptchaKey());
  39. if (!creds.getCaptcha().equals(captcha)) {
  40. logger.error("验证码不正确");
  41. throw new WelendException(StatusCode.CAPTCHA_ERROR);
  42. }
  43. }
  44. return authenticationManager.authenticate(
  45. new UsernamePasswordAuthenticationToken(
  46. creds.getUsername(),
  47. creds.getPassword(),
  48. new ArrayList<>())
  49. );
  50. } catch (IOException e) {
  51. logger.error("Client's variables can't be parsed by com.fasterxml.jackson.core.JsonParse");
  52. throw new WelendException(StatusCode.SERVER_ERROR);
  53. }
  54.  
  55. }
  56. }

验证用户名 密码:

  1. public class CustomAuthenticationProvider implements AuthenticationProvider {
  2.  
  3. private UserDetailsServiceImpl userDetailsService;
  4.  
  5. private BCryptPasswordEncoder bCryptPasswordEncoder;
  6.  
  7. public CustomAuthenticationProvider(UserDetailsServiceImpl userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
  8. this.userDetailsService = userDetailsService;
  9. this.bCryptPasswordEncoder = bCryptPasswordEncoder;
  10. }
  11.  
  12. @Override
  13. public Authentication authenticate(Authentication authentication) throws AuthenticationException {
  14. // 获取认证的用户名 & 密码
  15. String name = authentication.getName();
  16. String password = authentication.getCredentials().toString();
  17. // 认证逻辑
  18. JWTUserDetails userDetails = userDetailsService.loadUserByUsername(name);
  19. if (null != userDetails) {
  20. Boolean verifyPwd = bCryptPasswordEncoder.matches(password,userDetails.getLoginPwd());
  21. if (verifyPwd) {
  22. // 生成令牌 这里令牌里面存入了:userDetails,password,authorities(权限列表)
  23. Authentication auth = new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
  24. return auth;
  25. } else {
  26. throw new BadCredentialsException("username or password wrong!");
  27. }
  28. } else {
  29. throw new UsernameNotFoundException("can not find this account");
  30. }
  31. }
  32.  
  33. /**
  34. * 是否可以提供输入类型的认证服务
  35. * @param authentication
  36. * @return
  37. */
  38. @Override
  39. public boolean supports(Class<?> authentication) {
  40. return authentication.equals(UsernamePasswordAuthenticationToken.class);
  41. }
  42.  
  43. }

全局异常处理

  1. @RestControllerAdvice
  2. public class GlobalExceptionHandler {
  3. private Logger logger = LoggerFactory.getLogger(getClass());
  4.  
  5. /**
  6. * @param request
  7. * @param exception
  8. * @return
  9. * @throws Exception
  10. * @// TODO: 2018/4/25 参数未通过验证异常
  11. */
  12. @ExceptionHandler(value = MethodArgumentNotValidException.class)
  13. public Object MethodArgumentNotValidHandler(HttpServletRequest request, MethodArgumentNotValidException exception) throws Exception {
  14. //按需重新封装需要返回的错误信息
  15. //List<StatusCode> invalidArguments = new ArrayList<>();
  16. //解析原错误信息,封装后返回,此处返回非法的字段名称,原始值,错误信息
  17. ResultObject resultMsg = ResultObject.dataMsg(exception.getBindingResult().getFieldError().getDefaultMessage(), StatusCode.VARIABLE_ERROR);
  18. return resultMsg;
  19. }
  20.  
  21. /**
  22. * @param request
  23. * @param exception
  24. * @return
  25. * @throws Exception
  26. * @// TODO: 2018/4/25 无法解析参数异常
  27. */
  28. @ExceptionHandler(value = HttpMessageNotReadableException.class)
  29. public Object HttpMessageNotReadableHandler(HttpServletRequest request, HttpMessageNotReadableException exception) throws Exception {
  30. logger.info(exception.getMessage());
  31. ResultObject resultMsg = ResultObject.dataMsg("参数无法正常解析", StatusCode.VARIABLE_ERROR);
  32. return resultMsg;
  33. }
  34.  
  35. /**
  36. * @param exception
  37. * @return
  38. * @throws Exception
  39. * @// TODO: 2018/4/25 处理token 过期异常
  40. */
  41. @ExceptionHandler(value = ExpiredJwtException.class)
  42. public Object ExpiredJwtExceptionHandler(ExpiredJwtException exception) throws Exception {
  43. logger.info(exception.getMessage());
  44. ResultObject resultMsg = ResultObject.dataMsg("登录已过期!", StatusCode.FORBIDDEN);
  45. return resultMsg;
  46. }
  47.  
  48. /**
  49. * @param request
  50. * @param exception
  51. * @return
  52. * @throws Exception
  53. * @// TODO: 2018/4/25 方法访问权限不足异常
  54. */
  55. @ExceptionHandler(value = AccessDeniedException.class)
  56. public Object AccessDeniedExceptionHandler(AccessDeniedException exception) throws Exception {
  57. logger.info(exception.getMessage());
  58. ResultObject resultMsg = ResultObject.dataMsg("权限不足!", StatusCode.FORBIDDEN);
  59. return resultMsg;
  60. }
  61.  
  62. @ExceptionHandler(value = NoHandlerFoundException.class)
  63. public Object NoHandlerFoundExceptionHandler(NoHandlerFoundException exception) throws Exception {
  64. logger.info(exception.getMessage());
  65. return ResultObject.dataMsg("链接不存在", StatusCode.NOT_FOUND);
  66. }
  67. /**
  68. * 处理自定义异常
  69. */
  70. @ExceptionHandler(value = WelendException.class)
  71. public Object WelendExceptionHandler(WelendException e) {
  72. ResultObject r = new ResultObject();
  73. r.setStatus(String.valueOf(e.getCode()));
  74. r.setMessage(e.getMessage());
  75. return r;
  76. }
  77.  
  78. @ExceptionHandler(value = AuthenticationException.class)
  79. public Object AuthenticationExceptionHandler(AuthenticationException e) {
  80. return ResultObject.dataMsg(e.getLocalizedMessage(),StatusCode.FORBIDDEN);
  81. }
  82.  
  83. @ExceptionHandler(value = DuplicateKeyException.class)
  84. public Object DuplicateKeyExceptionHandler(DuplicateKeyException e) throws Exception {
  85. logger.error(e.getMessage(), e);
  86. return ResultObject.codeMsg(StatusCode.EXISTED);
  87. }
  88.  
  89. @ExceptionHandler(value = BadCredentialsException.class)
  90. public Object BadCredentialsExceptionHandler(BadCredentialsException e) throws Exception {
  91. logger.error(e.getMessage(), e);
  92. return ResultObject.codeMsg(StatusCode.AUTH_ERROR);
  93. }
  94.  
  95. @ExceptionHandler(value = Exception.class)
  96. public Object ExceptionHandler(Exception e) throws Exception {
  97. logger.error(e.getMessage(), e);
  98. return ResultObject.codeMsg(StatusCode.FAILED);
  99. }
  100. }

登录时输入错误的用户名

控制台直接打印信息了, 并没有经过ExceptionHandler 处理。

如上所示,我想在全局异常类中 处理spring security抛出异常, 以便返回友好的提示信息。有什么解决办法么?

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

  1. Spring boot 多模块项目 + Swagger 让你的API可视化

    Spring boot 多模块项目 + Swagger 让你的API可视化 前言 手写 Api 文档的几个痛点: 文档需要更新的时候,需要再次发送一份给前端,也就是文档更新交流不及时. 接口返回结果不 ...

  2. 【建议收藏】缺少 Vue3 和 Spring Boot 的实战项目经验?我这儿有啊!

    缺少 Vue3 和 Spring Boot 的实战项目经验?缺少学习项目和练手项目?我这儿有啊! 从 2019 年到 2021 年,空闲时间里陆陆续续做了一些开源项目,推荐给大家啊!记得点赞和收藏噢! ...

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

    前言 距离上一篇已经比较久的时间了,项目也是开了个头.并且,由于网上的关于Spring Boot的websocket讲解也比较多.于是我采用了另外的一个通讯框架 t-io 来实现LayIM中的通讯功能 ...

  4. 从零一起学Spring Boot之LayIM项目长成记(四) Spring Boot JPA 深入了解

    前言 本篇内容主要是一些关于JPA的常用的一些用法等.内容也是很多是看其他博客学来的,顺道在本系列博客里抽出一篇作为总结.下面让我们来看看吧. 不过我更推荐大家读本篇:https://lufficc. ...

  5. 从零一起学Spring Boot之LayIM项目长成记(三) 数据库的简单设计和JPA的简单使用。

    前言 今天是第三篇了,上一篇简单模拟了数据,实现了LayIM页面的数据加载.那么今天呢就要用数据库的数据了.闲言少叙,书归正传,让我们开始吧. 数据库 之前有好多小伙伴问我数据库是怎么设计的.我个人用 ...

  6. Spring Boot 2.0系列文章(五):Spring Boot 2.0 项目源码结构预览

    关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/15/springboot2_code/ 项目结构 结构分析: Spring-boot-pr ...

  7. 使用Spring Boot开发Web项目(二)之添加HTTPS支持

    上篇博客使用Spring Boot开发Web项目我们简单介绍了使用如何使用Spring Boot创建一个使用了Thymeleaf模板引擎的Web项目,当然这还远远不够.今天我们再来看看如何给我们的We ...

  8. 使用Spring Boot开发Web项目

    前面两篇博客中我们简单介绍了Spring Boot项目的创建.并且也带小伙伴们来DIY了一个Spring Boot自动配置功能,那么这些东西说到底最终还是要回归到Web上才能体现出它的更大的价值,so ...

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

    1. 利用spring boot提供的工具(http://start.spring.io/)自动生成一个标准的spring boot项目架构 2. 因为这里我们是搭建spring boot+mybat ...

随机推荐

  1. (Go)06. Printf格式化输出、Scanf格式化输入详解

    Print.Println .Printf .Sprintf .Fprintf都是fmt 包中的公共方法,在需要打印信息时需要用到这些函数,那么这些函数有什么区别呢? Print: 输出到控制台(不接 ...

  2. PCB MongoDB数据库 备份与还原

    一. MongoDB数据库 备份与还原工具介绍: 数据备份工具  mongodump.exe 数据还原工具   mongorestore.exe 二. MongoDB数据库备份 mongodump - ...

  3. bzoj2822[AHOI2012]树屋阶梯(卡特兰数)

    2822: [AHOI2012]树屋阶梯 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 879  Solved: 513[Submit][Status] ...

  4. mybatis的二级缓存

    在mybatis主配置文件里configuration标签里添加 <settings> <setting name="cacheEnabled" value=&q ...

  5. SpringCloud(二) 服务注册与发现Eureka

    1.eureka是干什么的? 上篇说了,微服务之间需要互相之间通信,那么通信就需要各种网络信息,我们可以通过使用硬编码的方式来进行通信,但是这种方式显然不合适,不可能说一个微服务的地址发生变动,那么整 ...

  6. 脑洞大开加偏执人格——可持久化treap版的Link Cut Tree

    一直没有点动态树这个科技树,因为听说只能用Splay,用Treap的话多一个log.有一天脑洞大开,想到也许Treap也能从底向上Split.仔细思考了一下,发现翻转标记不好写,再仔细思考了一下,发现 ...

  7. java热部署

    最近使用java做项目,研究了一下热部署,能够提高工作效率. 需要准备的工具: 1.安装文件http://update.zeroturnaround.com/update-site/ 2.破解 下载破 ...

  8. MVC微信浏览器图片上传(img转Base64)

    因公司业务需要,需要做一个微信公众号里的图片上传功能,主要用到的技术就是 img转base64 上到服务器 话不多说, 贴代码 先看前端显示出来的东西 OK 图片不重要,看代码 <!--微信图片 ...

  9. CSS元素水平垂直居中的方法

    1.  元素水平居中 1.1  设置父元素的属性 text-align: center; 说明:此属性只针对父元素的子元素为内联元素时有效,比如:img,input,select,button等(行内 ...

  10. JavaScript 浏览器事件解读

    1. 事件基本概念 事件是指在文档或者浏览器中发生的一些特定交互瞬间,比如打开某一个网页,浏览器加载完成后会触发 load 事件,当鼠标悬浮于某一个元素上时会触发 hover 事件,当鼠标点击某一个元 ...