这个异常是在登录的时候出现错误时抛出的异常,比如账户锁定,证书失效等,先来看下AuthenticationException常用的的子类:

UsernameNotFoundException 用户找不到

BadCredentialsException 坏的凭据

AccountStatusException 用户状态异常它包含如下子类

AccountExpiredException 账户过期

LockedException 账户锁定

DisabledException 账户不可用

CredentialsExpiredException 证书过期


常见的异常就这几个,还有很多不再一一赘述,仅仅为了展示,对后续的阅读没有什么影响

用户登录验证的过滤器是UsernamePasswordAuthenticationFilter,它继承自AbstractAuthenticationProcessingFilter。

今天研究的是看Spring如何处理AuthenticationException这个异常的,异常的处理一般都是doFilter中处理的,所以首先看AbstractAuthenticationProcessingFilter的doFilter中的代码

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {.......try {authResult = attemptAuthentication(request, response);if (authResult == null) {// return immediately as subclass has indicated that it hasn't completed authenticationreturn;}sessionStrategy.onAuthentication(authResult, request, response);} catch(InternalAuthenticationServiceException failed) {logger.error("An internal error occurred while trying to authenticate the user.", failed);unsuccessfulAuthentication(request, response, failed);return;}catch (AuthenticationException failed) {// Authentication failedunsuccessfulAuthentication(request, response, failed);return;}......}

从这段代码中我们看到Spring将异常捕获后交给了unsuccessfulAuthentication这个方法来处理(InternalAuthenticationServiceException也是AuthenticationException异常的子类,这是一个内部认证服务异常)

    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,AuthenticationException failed) throws IOException, ServletException {SecurityContextHolder.clearContext();if (logger.isDebugEnabled()) {logger.debug("Authentication request failed: " + failed.toString());logger.debug("Updated SecurityContextHolder to contain null Authentication");logger.debug("Delegating to authentication failure handler " + failureHandler);}rememberMeServices.loginFail(request, response);failureHandler.onAuthenticationFailure(request, response, failed);}

unsuccessfulAuthentication又交给了failureHandler(AuthenticationFailureHandler)来处理,然后追踪failureHandler

private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();

发现最终是由SimpleUrlAuthenticationFailureHandler这个类的onAuthenticationFailure方法来处理的,打开这个类,有两个核心方法

   public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,AuthenticationException exception) throws IOException, ServletException {if (defaultFailureUrl == null) {logger.debug("No failure URL set, sending 401 Unauthorized error");response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed: " + exception.getMessage());} else {saveException(request, exception);if (forwardToDestination) {logger.debug("Forwarding to " + defaultFailureUrl);request.getRequestDispatcher(defaultFailureUrl).forward(request, response);} else {logger.debug("Redirecting to " + defaultFailureUrl);redirectStrategy.sendRedirect(request, response, defaultFailureUrl);}}}/*** Caches the {@code AuthenticationException} for use in view rendering.* <p>* If {@code forwardToDestination} is set to true, request scope will be used, otherwise it will attempt to store* the exception in the session. If there is no session and {@code allowSessionCreation} is {@code true} a session* will be created. Otherwise the exception will not be stored.*/protected final void saveException(HttpServletRequest request, AuthenticationException exception) {if (forwardToDestination) {request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);} else {HttpSession session = request.getSession(false);if (session != null || allowSessionCreation) {request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);}}}

从onAuthenticationFailure中我们可以看出,如果没有设置defaultFailureUrl就发出401错误。(SC_UNAUTHORIZED是一个常量值是401),如果设置了defaultFailureUrl,调用saveException方法后跳转到defaultFailureUrl页面。

forwardToDestination是是否是服务器跳转,默认使用重定向即客户端跳转。

saveException字面意思是保存异常信息,其实就是把异常信息写入request或者Session中。

如果使用服务器跳转则写入request,客户端跳转则写入Session。

而key是WebAttributes.AUTHENTICATION_EXCEPTION打开WebAttributes找到这个常量

public final class WebAttributes {public static final String ACCESS_DENIED_403 = "SPRING_SECURITY_403_EXCEPTION";public static final String AUTHENTICATION_EXCEPTION = "SPRING_SECURITY_LAST_EXCEPTION";public static final String WEB_INVOCATION_PRIVILEGE_EVALUATOR_ATTRIBUTE = WebAttributes.class.getName() + ".WEB_INVOCATION_PRIVILEGE_EVALUATOR_ATTRIBUTE";
}

发现其值为SPRING_SECURITY_LAST_EXCEPTION,这样的话我们就可以在页面上通过el表达式来获取到这个异常了

注意:saveException保存的是Session对象所以直接使用 ${SPRING_SECURITY_LAST_EXCEPTION}是获取不到异常信息的,需要使用${SPRING_SECURITY_LAST_EXCEPTION.message}



Spring Security教程外篇(1)---- AuthenticationException异常详解相关推荐

  1. SpringBoot非官方教程 | 第二篇:SpringBoot配置文件详解

    springboot采纳了建立生产就绪Spring应用程序的观点. Spring Boot优先于配置的惯例,旨在让您尽快启动和运行.在一般情况下,我们不需要做太多的配置就能够让spring boot正 ...

  2. Spring Boot教程(十七)属性配置文件详解(2)

    通过命令行设置属性值 相信使用过一段时间Spring Boot的用户,一定知道这条命令:java -jar xxx.jar --server.port=8888,通过使用–server.port属性来 ...

  3. Spring Security教程

    Spring Security教程 Web系统中登录认证(Authentication)的核心就是凭证机制,无论是Session还是JWT,都是在用户成功登录时返回给用户一个凭证,后续用户访问接口需携 ...

  4. Spring Security 教程

    Spring Security 教程 在这篇文章中,我们将讨论Spring框架 "安全性"模块基础知识.我们将在即将发布的帖子中开发一些简单而先进的示例. 现在,开发安全应用程序是 ...

  5. 循序渐进学spring security 第八篇,如何配置密码加密?是否支持多种加密方案?

    文章目录 回顾 密码明文会带来什么问题? 如何加密? PasswordEncoder 加密接口 如何配置? 加密的密码在登录的时候是怎么校验的? 默认的加密是什么? DaoAuthentication ...

  6. 史上最简单的Spring Security教程(十九):AccessDecisionVoter简介及自定义访问权限投票器

    为了后续对 AccessDecisionManager 的介绍,我们先来提前对 AccessDecisionVoter 做个简单的了解,然后,在捎带手自定义一个 AccessDecisionVoter ...

  7. 【STM32】STM32标准库与HAL库对照学习教程特别篇--系统时钟RCC详讲

    [STM32]STM32标准库与HAL库对照学习教程特别篇--系统时钟RCC详讲 一.前言 二.时钟是什么 三.时钟树 1.时钟树图 2.时钟树讲解 左边部分 中间部分 右边部分 特殊部分 四.初始化 ...

  8. 【夯实Spring Cloud】Spring Cloud中使用Hystrix实现断路器原理详解(上)

    本文属于[夯实Spring Cloud]系列文章,该系列旨在用通俗易懂的语言,带大家了解和学习Spring Cloud技术,希望能给读者带来一些干货.系列目录如下: [夯实Spring Cloud]D ...

  9. php laravel入口文件,Laravel学习教程之从入口到输出过程详解

    php 的 Laravel学习教程之从入口到输出过程详解 本文主要给大家介绍了关于Laravel从入口到输出过程的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. I. 预备 ...

最新文章

  1. OpenCV+python:模板匹配
  2. Cannot add or update a child row:
  3. JZOJ 5456. 【NOIP2017提高A组冲刺11.6】奇怪的队列
  4. mysql的单个数据库物理迁移出现ERROR 1146 (42S02): Table 'xx' doesn't exist [问题点数:100分]...
  5. ios 动画 隐藏tabbar_UITabBarViewController 的底部 tabBar 隐藏
  6. 23种设计模式(5)-适配器模式
  7. 附录-系统环境、系统属性
  8. SSH启动失败解决方法
  9. Windows软件防火墙实现技术简述
  10. java xml注释多行_如何在XML中注释单行?
  11. 基于LabVIEW 2018开发的自动化测试系统源码,该系统模仿TestStand编写
  12. 计算机程序设计实验报告总结,c语言实验总结(大一c语言实验报告总结)
  13. LeeCode 130 DFS
  14. 考研题目 第五章 数组和广义表
  15. YARN原理及工作流程详解
  16. PMP知识点:项目成本管理计算公式
  17. SQL Server 索引碎片和填充因子
  18. 《网络攻防》第二周作业
  19. (OS 10038)在一个非套接字上尝试了一个操作 的解决办法
  20. Microblaze程序固化流程

热门文章

  1. Relational Graph Attention Network for Aspect-based Sentiment Analysis
  2. 数据结构与算法基础--王卓
  3. Adaptive Deconvolutional Networks for Mid and High Level Feature Learning(阅读)
  4. VGG19模型训练+读取
  5. linux oracle按钮乱码,oracle em 按钮乱码现象
  6. 数据结构--抽象数据类型三元组Triplet的表示和实现
  7. Windows CMD常用命令查询
  8. 局域网下怎样访问另一台电脑的服务
  9. STM32F103C8T6继电器驱动篇
  10. 我的JAVA面试题备忘录