• SpringSecurity系列——认证(Authentication)架构day2-3(源于官网5.7.2版本)


    前言

    源于官方最新5.7.2文档,若你觉得官方文档阅读起来很枯燥,内容复杂,我提供了解析概括在每个部分的结尾,我对官方文档的内容做了一些改变,实例代码我会在后续进行更新,请查看如:SpringSecurity系列——认证架构实例代码的文章

    但是如果你有能力,还是推荐直接阅读官方文档

    Authentication(认证)

    身份验证的目的

    身份验证在 Spring Security 中有两个主要目的:

    1. AuthenticationManager 的输入,用于提供用户提供的身份验证凭据。 在这种情况下使用时,isAuthenticated() 返回 false。

    2. 表示当前经过身份验证的用户。 当前的Authentication可以从SecurityContext中获取。

    身份验证包含:

    1. 主体 - 标识用户。 当使用用户名/密码进行身份验证时,这通常是 UserDetails 的一个实例。
    2. 凭据 - 通常是密码。 在许多情况下,这将在用户通过身份验证后被清除,以确保它不被泄露。
    3. authority - GrantedAuthoritys 是授予用户的高级权限。 一些示例是角色或范围。

    授权

    Servlet身份认证架构

    • SecurityContextHolder - SecurityContextHolder 是 Spring Security 存储身份验证者详细信息的地方。

    • SecurityContext - 从 SecurityContextHolder 中获取,包含当前经过身份验证的用户的身份验证。

    • 身份验证 - 可以是 AuthenticationManager 的输入,以提供用户提供的用于身份验证的凭据或来自 SecurityContext 的当前用户。

    • GrantedAuthority - 在身份验证上授予主体的权限(即角色、范围等)

    • AuthenticationManager - 定义 Spring Security 的过滤器如何执行身份验证的 API。

    • ProviderManager - AuthenticationManager 最常见的实现。

    • AuthenticationProvider - ProviderManager 使用它来执行特定类型的身份验证。

    • Request Credentials with AuthenticationEntryPoint - 用于从客户端请求凭据(即重定向到登录页面、发送 WWW-Authenticate 响应等)

    • AbstractAuthenticationProcessingFilter - 用于身份验证的基本过滤器。 这也很好地了解了身份验证的高级流程以及各个部分如何协同工作。

    SecurityContextHolder(安全上下文持有者)

    Spring Security 认证模型的核心是 SecurityContextHolder。 它包含 SecurityContext。
    在这里插入图片描述
    SecurityContextHolder 是 Spring Security 存储身份验证者详细信息的地方。 Spring Security 不关心 SecurityContextHolder 是如何填充的,如果它包含一个值,则将其用作当前经过身份验证的用户。

    指示用户已通过身份验证的最简单方法是直接设置SecurityContextHolder

    设置SecurityContextHolder

    SecurityContext context = SecurityContextHolder.createEmptyContext();
    Authentication authentication =
        new TestingAuthenticationToken("username", "password", "ROLE_USER");
    context.setAuthentication(authentication);
    
    SecurityContextHolder.setContext(context);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 我们首先创建一个空的 SecurityContext。 重要的是创建一个新的 SecurityContext 实例而不是使用 SecurityContextHolder.getContext().setAuthentication(authentication) 以避免跨多个线程的竞争条件。
    • 接下来我们创建一个新的 Authentication 对象。 Spring Security 不关心 SecurityContext 上设置了哪种类型的身份验证实现。 这里我们使用 TestingAuthenticationToken 因为它非常简单。 更常见的生产场景是 UsernamePasswordAuthenticationToken(userDetails, password, authority)。
    • 最后,我们在 SecurityContextHolder 上设置 SecurityContext。 Spring Security 将使用此信息进行授权。

    如果您希望获取有关经过身份验证的主体的信息,可以通过访问 SecurityContextHolder 来实现。

    访问当前经过身份验证的用户

    SecurityContext context = SecurityContextHolder.getContext();
    Authentication authentication = context.getAuthentication();
    String username = authentication.getName();
    Object principal = authentication.getPrincipal();
    Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    默认情况下,SecurityContextHolder 使用 ThreadLocal 来存储这些详细信息,这意味着 SecurityContext 始终可用于同一线程中的方法,即使 SecurityContext 没有明确地作为参数传递给这些方法。 如果在处理当前主体的请求后注意清除线程,那么以这种方式使用 ThreadLocal 是非常安全的。 Spring Security 的 FilterChainProxy 确保 SecurityContext 总是被清除。

    SecurityContextHolder 可以在启动时配置一个策略,以指定您希望如何存储上下文。 对于独立应用程序,您将使用 SecurityContextHolder.MODE_GLOBAL 策略。 其他应用程序可能希望安全线程产生的线程也采用相同的安全身份。 这是通过使用 SecurityContextHolder.MODE_INHERITABLETHREADLOCAL 来实现的。 您可以通过两种方式从默认的 SecurityContextHolder.MODE_THREADLOCAL 更改模式。 第一个是设置系统属性,第二个是调用SecurityContextHolder的静态方法。 大多数应用程序不需要更改默认设置,但如果您这样做,请查看 Javadoc for SecurityContextHolder 以了解更多信息。

    解释概括

    1. SecurityContextHolder是认证的核心,存储了经过认证的用户信息,他包含SecurityContext(安全上下文)
    2. SpringSecurity只要发现SecurityContextHolder中有值,就当做当前已通过认证的用户,其他一概不管
    3. UsernamePasswordAuthenticationToken(userDetails, password, authority)是我们在生产环境中最常使用到的身份验证的实现
    4. 通过获取SecurityContextHolder就能获取当前通过认证的用户信息
    5. SecurityContextHolder是线程隔离的(使用了ThreadLocal)
    6. 在最后会调用FilterChainProxy来清除SecurityContext的信息确保安全

    SecurityContext(安全上下文)

    SecurityContext 是从 SecurityContextHolder 获得的。 SecurityContext 包含一个 Authentication 对象,是当前经过身份验证的用户的身份验证。

    AuthenticationManager(身份验证管理器


    AuthenticationManager 是定义 Spring Security 的过滤器如何执行身份验证的 API。 然后由调用 AuthenticationManager 的控制器(即 Spring Security 的 Filters)在 SecurityContextHolder 上设置返回的 Authentication。 如果你没有与 Spring Security 的 Filters 集成,你可以直接设置 SecurityContextHolder 并且不需要使用 AuthenticationManager。

    虽然 AuthenticationManager 的实现可以是任何东西,但最常见的实现是 ProviderManager。

    解释概括

    1. AuthenticationManager是Spring Security 的过滤器如何执行身份验证的 API
    2. 若没有对Spring Security 的 Filters 集成可以设置SecurityContextHolder不使用AuthenticationManager
    3. 我们常用ProviderManager而非AuthenticationManager

    ProviderManager(提供者管理器)

    ProviderManager 是 AuthenticationManager 最常用的实现。
    ProviderManager 委托给一个 AuthenticationProviders 列表。 每个 AuthenticationProvider 都有机会指示身份验证应该成功、失败或指示它无法做出决定并允许下游 AuthenticationProvider 做出决定。 如果配置的 AuthenticationProviders 都不能进行身份验证,则身份验证将失败并出现 ProviderNotFoundException,这是一个特殊的 AuthenticationException,表明 ProviderManager 未配置为支持传递给它的身份验证类型。
    在这里插入图片描述
    实际上,每个 AuthenticationProvider 都知道如何执行特定类型的身份验证。 例如,一个 AuthenticationProvider 可能能够验证用户名/密码,而另一个可能能够验证 SAML 断言。 这允许每个 AuthenticationProvider 执行非常特定类型的身份验证,同时支持多种类型的身份验证并且只公开单个 AuthenticationManager bean。

    ProviderManager 还允许配置一个可选的父 AuthenticationManager,如果没有 AuthenticationProvider 可以执行身份验证,则可以参考该父 AuthenticationManager。 父级可以是任何类型的 AuthenticationManager,但它通常是 ProviderManager 的一个实例。

    事实上,多个 ProviderManager 实例可能共享同一个父 AuthenticationManager。 这在有多个 SecurityFilterChain 实例具有一些共同的身份验证(共享父 AuthenticationManager)但也有不同的身份验证机制(不同的 ProviderManager 实例)的情况下有些常见。
    在这里插入图片描述
    默认情况下,ProviderManager 将尝试从成功的身份验证请求返回的 Authentication 对象中清除任何敏感的凭据信息。 这可以防止诸如密码之类的信息在 HttpSession 中保留的时间超过必要的时间。

    当您使用用户对象的缓存时,这可能会导致问题,例如,为了提高无状态应用程序的性能。 如果 Authentication 包含对缓存中对象的引用(例如 UserDetails 实例)并且已删除其凭据,则将不再可能针对缓存的值进行身份验证。 如果您使用缓存,则需要考虑到这一点。 一个明显的解决方案是首先在缓存实现中或在创建返回的 Authentication 对象的 AuthenticationProvider 中制作对象的副本。 或者,您可以禁用 ProviderManager 上的 eraseCredentialsAfterAuthentication 属性。 有关更多信息,请参阅 Javadoc。

    解释概括

    1. ProviderManager 是 AuthenticationManager 最常用的实现
    2. ProviderManager实际是对AuthenticationProvider列表进行管理调配的
    3. AuthenticationProvider指示身份验证应该成功、失败或指示它无法做出决定,若无法做出觉得则调用下一个AuthenticationProvider
    4. 若所有AuthenticationProvider判断失败则抛出ProviderNotFoundException,ProviderManager 未配置为支持传递给它的身份验证类型
    5. AuthenticationProvider可以对各种不同的验证方式起效但只公开单个 AuthenticationManager bean实例
    6. 在ProviderManager中若没有 AuthenticationProvider 可以执行身份验证,我们可以通过配置父级(AuthenticationManager)实现验证
    7. 多个ProviderManager可以只有一个父AuthenticationManager(且很常见)
    8. ProviderManager 默认从成功的身份验证请求返回的 Authentication 对象中清除任何敏感的凭据信息,以保证存留凭证超时

    AuthenticationProvider(身份验证提供者)

    可以将多个 AuthenticationProviders 注入 ProviderManager。 每个 AuthenticationProvider 执行特定类型的身份验证。 例如,DaoAuthenticationProvider 支持基于用户名/密码的身份验证,而 JwtAuthenticationProvider 支持对 JWT 令牌进行身份验证。

    Request Credentials with AuthenticationEntryPoint(使用 AuthenticationEntryPoint 请求凭据)

    AuthenticationEntryPoint 用于发送从客户端请求凭据的 HTTP 响应。

    有时,客户端会主动包含凭据(例如用户名/密码)来请求资源。 在这些情况下,Spring Security 不需要提供从客户端请求凭据的 HTTP 响应,因为它们已经包含在内。

    在其他情况下,客户端将对他们无权访问的资源发出未经身份验证的请求。 在这种情况下,AuthenticationEntryPoint 的实现用于从客户端请求凭据。 AuthenticationEntryPoint 实现可能会重定向到登录页面,使用 WWW-Authenticate 标头等进行响应。

    概括解释

    在实际应用的时候,当客户端传了一个已过期的凭证向服务端请求响应时,AuthenticationEntryPoint帮助我们直接拒绝并重定向至登录页面,强制用户重新登录来更新凭证

    AbstractAuthenticationProcessingFilter(抽象认证过程过滤器)

    AbstractAuthenticationProcessingFilter 用作验证用户凭据的基本过滤器。 在可以对凭据进行身份验证之前,Spring Security 通常使用 AuthenticationEntryPoint 请求凭据。

    接下来,AbstractAuthenticationProcessingFilter 可以对提交给它的任何身份验证请求进行身份验证。

    在这里插入图片描述

    1. 当用户提交他们的凭据时,AbstractAuthenticationProcessingFilter 从 HttpServletRequest 创建一个身份验证以进行身份​​验证。 创建的 Authentication 类型取决于 AbstractAuthenticationProcessingFilter 的子类。 例如,UsernamePasswordAuthenticationFilter 根据在HttpServletRequest 中提交的用户名和密码创建 UsernamePasswordAuthenticationToken

    2. 接下来,将 Authentication 传递到 AuthenticationManager 进行身份验证。

    3. 如果认证失败,则失败

      • SecurityContextHolder 被清除。
      • 调用 RememberMeServices.loginFail。 如果记住我没有配置,这是一个空操作。
      • AuthenticationFailureHandler 被调用。
    4. 如果认证成功,则为 Success。

      • SessionAuthenticationStrategy 收到新登录通知。
      • Authentication 在 SecurityContextHolder 上设置。 稍后SecurityContextPersistenceFilter 将 SecurityContext 保存到 HttpSession。
      • 调用 RememberMeServices.loginSuccess 如果记住我没有配置,这是一个空操作。
      • ApplicationEventPublisher 发布一个InteractiveAuthenticationSuccessEvent。
      • AuthenticationSuccessHandler 被调用。

    解释概述

    1. AbstractAuthenticationProcessingFilter 用作验证用户凭据的基本过滤器,将Authentication交由AuthenticationManager进行验证
    2. 用户提交凭据后AbstractAuthenticationProcessingFilter会从HttpServletRequest 创建一个身份验证以进行身份​​验证,验证类型取决于具体实现
    3. 验证失败会清除SecurityContextHolder ,调用 RememberMeServices.loginFail,调用AuthenticationFailureHandler
    4. 成功则进行登录,SecurityContextHolder接收Authentication传递,保存至HttpSession中,调用记住我的配置,应用时间发布者会发布交互认证成功事件,认证成功的处理会被调用
  • 相关阅读:
    vue3 props传值默认类型
    postgresql源码编译安装
    Linux学习笔记之设备驱动篇(3)_内核模块_实验篇
    Sublime text的使用及技巧积累
    YOLOv7-Pose尝鲜,基于YOLOv7的关键点模型测评
    屋顶太阳能光伏系统的性能分析指标研究
    【底层服务/编程功底系列】「大数据算法体系」带你深入分析MapReduce算法 — Shuffle的执行过程
    C++学习笔记(面向对象部分开始6500字复习总结)
    unity面试八股文 - 常用工具与算法
    IDEA的使用
  • 原文地址:https://blog.csdn.net/qq_51553982/article/details/125884356