文章目录

  • 一、常见异常
  • 二、源码分析
  • 三、处理异常
  • 四、拓展spring security authenticationProvider用法及关闭不隐藏UserNotFoundException的解决

不知道你有没有注意到,当我们登陆失败时候,Spring security 帮我们跳转到了 /login?error Url,奇怪的是不管是控制台还是网页上都没有打印错误信息。

这是因为首先 /login?error 是 Spring security 默认的失败 Url,其次如果你不手动处理这个异常,这个异常是不会被处理的。

代码地址:https://github.com/FadeHub/spring-boot-learn/tree/master/spring-boot-security-3

一、常见异常

我们先来列举下一些 Spring Security 中常见的异常:

  • UsernameNotFoundException(用户不存在)
  • DisabledException(用户已被禁用)
  • BadCredentialsException(坏的凭据)
  • LockedException(账户锁定)
  • AccountExpiredException (账户过期)
  • CredentialsExpiredException(证书过期)

  • 以上列出的这些异常都是 AuthenticationException 的子类,然后我们来看看 Spring security 如何处理 AuthenticationException 异常的。.

二、源码分析

我们知道异常处理一般在过滤器中处理,我们在 AbstractAuthenticationProcessingFilter 中找到了对 AuthenticationException 的处理:

(1)在 doFilter() 中,捕捉了 AuthenticationException 异常,并交给了 unsuccessfulAuthentication() 处理。

(2)在 unsuccessfulAuthentication() 中,转交给了 SimpleUrlAuthenticationFailureHandler 类的 onAuthenticationFailure() 处理。

(3)在onAuthenticationFailure()中,SimpleUrlAuthenticationFailureHandler实现类,首先判断有没有设置defaultFailureUrl。

如果没有设置,直接返回 401 错误,即 HttpStatus.UNAUTHORIZED 的值。

如果设置了,首先执行 saveException() 方法。然后判断 forwardToDestination ,即是否是服务器跳转,默认使用重定向即客户端跳转。

(4)在 saveException() 方法中,首先判断forwardToDestination,如果使用服务器跳转则写入 Request,客户端跳转则写入 Session。写入名为 SPRING_SECURITY_LAST_EXCEPTION ,值为 AuthenticationException。

至此 Spring security 完成了异常处理,总结一下流程:

–> AbstractAuthenticationProcessingFilter.doFilter()

–> AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication()

–> SimpleUrlAuthenticationFailureHandler.onAuthenticationFailure()

–> SimpleUrlAuthenticationFailureHandler.saveException()

三、处理异常

上面源码说了那么多,真正处理起来很简单,我们只需要指定错误的url,然后再该方法中对异常进行处理即可。

(1)指定错误Url,WebSecurityConfig中添加.failureUrl("/login/error")

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate CustomUserDetailsService userDetailsService;@Autowiredprivate DataSource dataSource;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.authenticationProvider(authenticationProvider());}@Beanpublic DaoAuthenticationProvider authenticationProvider() {DaoAuthenticationProvider provider = new DaoAuthenticationProvider();provider.setHideUserNotFoundExceptions(false);provider.setUserDetailsService(userDetailsService);provider.setPasswordEncoder(new PasswordEncoder() {@Overridepublic String encode(CharSequence charSequence) {return charSequence.toString();}@Overridepublic boolean matches(CharSequence charSequence, String s) {return s.equals(charSequence.toString());}});return provider;}/*** 数据库存储* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin().loginPage("/login")// 设置登陆成功页.defaultSuccessUrl("/").permitAll().failureHandler(new SimpleUrlAuthenticationFailureHandler())//登录失败url.failureForwardUrl("/login/error").and()// 自定义登陆用户名和密码参数,默认为username和password// .usernameParameter("username")//  .passwordParameter("password").logout().permitAll()//基于内存自动登录.and().rememberMe().tokenRepository(persistentTokenRepository()).tokenValiditySeconds(60)   ;http.csrf().disable();}@Beanpublic PersistentTokenRepository persistentTokenRepository() {JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();tokenRepository.setDataSource(dataSource);// 如果token表不存在,使用下面语句可以初始化该表;若存在,请注释掉这条语句,否则会报错。
//        tokenRepository.setCreateTableOnStartup(true);return tokenRepository;}@Overridepublic void configure(WebSecurity web) throws Exception {// 设置拦截忽略文件夹,可以对静态资源放行web.ignoring().antMatchers("/css/**", "/js/**");}}

对应Controller

 @RequestMapping("/login/error")public void loginError(HttpServletRequest  req, HttpServletResponse resp) {resp.setContentType("text/html;charset=utf-8");AuthenticationException exception =(AuthenticationException) req.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");try {resp.getWriter().write(exception.toString());}catch (IOException e) {e.printStackTrace();}}

一定是取req.getAttribuate(“SPRING_SECURITY_LAST_EXCEPTION”)才能取出异常信息。

四、拓展spring security authenticationProvider用法及关闭不隐藏UserNotFoundException的解决

问题是用户登录失败(用户不存在或密码错误)之后,security框架直接返回的是验证失败。而我的需求是将用户不存在和密码错误区分开来,然后做不同的后续工作。

用户不存在返回错误信息为:UsernameNotFoundException
密码错误返回错误信息为:BadCredentialsException

UserNotFoundException异常是在DaoAuthenticationProvider中被屏蔽掉的,而DaoAuthenticationProvider中有个属性hideUserNotFoundExceptions,默认是ture,也就是说要想抛出UserNotFoundException,需要把hideUserNotFoundExceptions设为false。
于是增加了一个DaoAuthenticationProvider的配置

 @Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.authenticationProvider(authenticationProvider());}@Beanpublic DaoAuthenticationProvider authenticationProvider() {DaoAuthenticationProvider provider = new DaoAuthenticationProvider();provider.setHideUserNotFoundExceptions(false);provider.setUserDetailsService(userDetailsService);provider.setPasswordEncoder(new PasswordEncoder() {@Overridepublic String encode(CharSequence charSequence) {return charSequence.toString();}@Overridepublic boolean matches(CharSequence charSequence, String s) {return s.equals(charSequence.toString());}});return provider;}

如果我们配置DaoAuthenticationProvider一定要把

auth .userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());

这两行代码删掉,否则还是不会返回我们希望的错误信息!!!

SpringBoot整合Spring Security——第三章异常处理相关推荐

  1. springBoot整合spring security+JWT实现单点登录与权限管理前后端分离

    在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与权限管理. ...

  2. springBoot整合spring security+JWT实现单点登录与权限管理前后端分离--筑基中期

    写在前面 在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与 ...

  3. SpringBoot 整合 Spring Security 实现安全认证【SpringBoot系列9】

    SpringCloud 大型系列课程正在制作中,欢迎大家关注与提意见. 程序员每天的CV 与 板砖,也要知其所以然,本系列课程可以帮助初学者学习 SpringBooot 项目开发 与 SpringCl ...

  4. SpringBoot整合Spring Security【超详细教程】

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/Lee/DayDayUP,欢迎Star,更多文章请前往:目录导航 前言 Spring Security是一个 ...

  5. 八、springboot整合Spring Security

    springboot整合Spring Security 简介 Spring Security是一个功能强大且可高度自定义的身份验证和访问控制框架.它是保护基于Spring的应用程序的事实标准. Spr ...

  6. SpringBoot 整合Spring Security(简单版)

    1 写在前面 关于spring security的介绍,网上一大堆,这里就不介绍了,这里直接使用springboot开始整合 2 整个流程 spring security授权和认证的流程大致和shir ...

  7. SpringBoot整合Spring Security——登录管理

    文章目录 一.自定义认证成功.失败处理 1.1 CustomAuthenticationSuccessHandle 1.2 CustomAuthenticationFailureHandler 1.3 ...

  8. SpringBoot集成Spring Security(3)——异常处理

    源码地址:https://github.com/jitwxs/blog_sample 文章目录 一.常见异常 二.源码分析 三.处理异常 不知道你有没有注意到,当我们登陆失败时候,Spring sec ...

  9. SpringBoot整合Spring Security

    个人资源与分享网站:http://xiaocaoshare.com/ SpringSecurity核心功能: 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) 1.pom.xml < ...

最新文章

  1. sql between 效率高吗_B2增驾好吗
  2. Hibernate配置数据源,数据库连接池
  3. Flask入门到放弃(四)—— 数据库
  4. Atitit.异常处理 嵌套  冗长的解决方案
  5. 海信新机F30S即将发布:搭载紫光展锐虎贲T310处理器
  6. CODE[VS] 1098 均分纸牌 ( 2002年NOIP全国联赛提高组)
  7. 【模拟】牛客网:顺时打印矩阵
  8. 录制线上课程,有哪些形式,到底使用什么软件好?
  9. HttpClient4
  10. 21克c1语言,C1人称代词
  11. centos7安装mysql5.7步骤(图解版)
  12. Python地学分析 — GDAL通过矢量裁剪遥感图像
  13. Eason's concert
  14. Windows 10 修改桌面图标一(系统图标)
  15. 赫夫曼压缩(萌新劝退)
  16. MFC-CString
  17. 如何给台式计算机风扇加油,如何给电风扇加油呢?教你一些技巧
  18. java使用freemarker导出word标题失效问题
  19. 无数人扎堆计算机视觉,但这家公司却聚焦决策智能
  20. opencv图像处理几种常见滤波器实现

热门文章

  1. MFC之ComboBox控件用法
  2. tensorflow2调用huggingface transformer预训练模型
  3. 桂林电子科技大学 计算机学院,桂林电子科技大学信息科技学院
  4. 如何将catia装配件附材料_在网上买的快餐桌椅如何安装?餐厅快餐桌椅安装顺序与流程知识...
  5. Java基础day3
  6. 农村研究生复试331分逆袭390分引质疑?北京协和医学院回应
  7. 【机器学习基础】一文归纳AI数据增强之法
  8. 【机器学习基础】理解关联规则算法
  9. 【论文解读】何恺明团队最新力作SimSiam:消除表征学习“崩溃解”,探寻对比表达学习成功之根源...
  10. Python地信专题 | 基于geopandas的空间数据分析—数据结构篇