Spring Security框架认证整体梳理
发布日期:2021-06-29 15:52:27 浏览次数:3 分类:技术文章

本文共 8890 字,大约阅读时间需要 29 分钟。

Spring Security提供了对身份验证的全面支持。本部分内容包含:

  • 架构组件:Spring Security在Servlet身份验证中使用的主要架构组件

    • -SecurityContextHolder是Spring Security存储身份认证的详细信息的地方。
    • -从SecurityContextHolder中获取,包含当前认证用户的Authentication信息。
    • - 可以是AuthenticationManager的输入,以提供用户已提供的用于身份验证的凭据,也可以是来自SecurityContext的当前用户。
    • - 在身份验证中授予主体的权限
    • - 定义Spring Security的Filter如何执行认证的API。
    • - AuthenticationManager最常见的实现
    • - 由ProviderManager用于执行特定类型的身份认证。
    • - 用于从客户端请求凭证(即重定向到一个登录页面,发送一个WWW-Authenticate响应,等等)。
    • - 用于身份验证的基本Filter。这还可以很好地了解高层次的身份验证流程以及各个部分如何协同工作。
  • 认证机制

    • - 如何使用用户名和密码认证
    • - OAuth 2.0使用OpenID登录连接和非标准的OAuth 2.0登录
    • - SAML 2.0 登录
    • - Central Authentication Server (CAS) 支持
    • - 如何记住用户会话过期
    • - JAAS 认证
    • - OpenID 认证 (不要与OpenID连接混淆)
    • - 使用外部机制(如SiteMinder或Java EE安全性)进行身份验证,但仍然使用Spring security进行授权和保护,以防止常见攻击。
    • - X509 认证

SecurityContextHolder

Spring Security的身份验证模型的核心是SecurityContextHolder。它包含SecurityContext

在这里插入图片描述

SecurityContextHolder是Spring Security存储身份验证的详细信息的地方。Spring Security并不关心SecurityContextHolder是如何构成的。如果它包含一个值,那么它就被用作当前经过身份验证的用户。

配置SecurityContextHolder

SecurityContext context = SecurityContextHolder.createEmptyContext(); Authentication authentication =    new TestingAuthenticationToken("username", "password", "ROLE_USER"); context.setAuthentication(authentication);SecurityContextHolder.setContext(context);

程序中获取SecurityContextHolde

SecurityContext context = SecurityContextHolder.getContext();Authentication authentication = context.getAuthentication();String username = authentication.getName();Object principal = authentication.getPrincipal();Collection
authorities = authentication.getAuthorities();
  • 默认情况下,SecurityContextHolder使用ThreadLocal来存储这些详细信息,这意味着SecurityContext对于同一个执行线程中的方法总是可用的,即使SecurityContext没有显式地作为参数传递给这些方法。以这种方式使用ThreadLocal是相当安全的。Spring Security的FilterChainProxy确保SecurityContext总是会被清除。

  • 有些应用程序并不完全适合使用ThreadLocal。例如,Swing客户端可能希望Java虚拟机中的所有线程都使用相同的 security context。SecurityContextHolder可以在启动时配置一个策略,以指定您希望如何存储上下文。对于独立的应用程序,将使用SecurityContextHolder.MODE_GLOBAL策略。其他应用程序可能希望安全线程生成的线程也采用相同的安全标识。这是通过使用SecurityContexHolder .MODE_INHERITABLETHREADLOCAL实现的。

  • 可以通过两种方式更改默认的SecurityContextHolder.MODE_THREADLOCAL。第一个是设置系统属性,第二个是调用SecurityContextHolder上的静态方法。

  • 大多数应用程序不需要更改默认设置

SecurityContext

SecurityContextSecurityContextHolder中获取。SecurityContext包含一个Authentication对象。

Authentication

在Spring Security中,Authentication有两个主要目的:

  • AuthenticationManager的一个输入,用于提供用户为进行身份验证而提供的凭据。在此场景中使用时,isAuthenticated()返回false

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

Authentication包含:

  • principal - 识别用户。当使用用户名/密码进行身份验证时,这通常是UserDetails的一个实例。
  • credentials - 通常一个密码。在许多情况下,这将在用户身份验证后清除,以确保不会泄漏。
  • authorities - 是授予用户的高级权限。例如角色或作用域。

GrantedAuthority

GrantedAuthority为用户被授予的高级权限。

  • GrantedAuthority可以从Authentication.getAuthorities()方法中获取.

  • 权限的角色表示,例如ROLE_ADMINISTRATORROLE_HR_SUPERVISOR

  • 使用用户名/密码的身份验证时,GrantedAuthority通常由UserDetailsService加载

  • 通常权限是应用范围内的,没有给定对象的权限 (例如 特定id的User对象的权限)

AuthenticationManager

AuthenticationManager定义了Spring Security的Filter如何进行认证。

常用实现类为ProviderManager

ProviderManager

ProviderManagerAuthenticationManager最常用的实现。

ProviderManager委托给AuthenticationProvider列表,

  • 每个AuthenticationProvider都有机会表明身份验证应该是成功的,失败的,
  • 或者表明它不能做出决定,并允许下游的AuthenticationProvider来做出决定
  • 如果没有AuthenticationProvider可以认证,ProviderNotFoundException则抛出异常

在这里插入图片描述

实际上,每个AuthenticationProvider都知道如何执行特定类型的身份验证。

例如,一个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属性。

AuthenticationProvider

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

AuthenticationEntryPoint

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

AbstractAuthenticationProcessingFilter

AbstractAuthenticationProcessingFilter被用作验证用户凭据的基本Filter。在验证凭据之前,Spring Security通常使用AuthenticationEntryPoint请求凭据。接下来,AbstractAuthenticationProcessingFilter可以验证提交给它的任何身份验证请求。

在这里插入图片描述

①当用户提交他们的凭据时,AbstractAuthenticationProcessingFilterHttpServletRequest创建一个身份验证来进行身份验证。创建的身份验证类型依赖于AbstractAuthenticationProcessingFilter的子类。例如,UsernamePasswordAuthenticationFilterHttpServletRequest中提交的用户名和密码创建UsernamePasswordAuthenticationToken

Authentication交给AuthenticationManager去进行认证

③认证失败,依次执行:

  • SecurityContextHolder清理
  • RememberMeServices.loginFail开始执行,如果没有配置则无操作
  • AuthenticationFailureHandler执行

④认证成功,依次执行:

  • SessionAuthenticationStrategy接受到新的登录通知
  • Authentication 配置到 SecurityContextHolder中,之后SecurityContextPersistenceFilterSecurityContext保存到HttpSession.
  • RememberMeServices.loginSuccess 执行,没有配置则无操作
  • ApplicationEventPublisher发布一个InteractiveAuthenticationSuccessEvent

Username/Password Authentication

这部分内容较多,参考我的另一篇文章

Session Management

HTTP会话相关的功能是通过SessionManagementFilterSessionAuthenticationStrategy接口的组合来处理的,该接口由过滤器委托给它。典型的应用包括会话固定保护、攻击预防、会话超时检测和限制通过身份验证的用户可以同时打开的会话数量。

可以实现下面功能

  • 检测超时
  • 并发会话控制
  • 会话固定攻击防护

Remember-Me认证

记住我或持久登录身份验证指的是网站能够在会话之间记住主体的身份。这通常是通过向浏览器发送cookie来完成的,在未来的会话中检测到cookie可以自动登录。

Spring Security有两个具体的remember-me实现。

  • 一个使用散列来保护基于cookie的令牌的安全性,
  • 使用数据库或其他持久存储机制来存储生成的令牌。

注意,两个实现都需要一个UserDetailsService。如果您使用的身份验证提供程序不使用UserDetailsService(例如,LDAP提供程序),那么它将无法工作,除非您的应用程序上下文中也有UserDetailsService bean。

基于Hash的Token

cookie组成

base64(username + ":" + expirationTime + ":" +md5Hex(username + ":" + expirationTime + ":" password + ":" + key))username:          As identifiable to the UserDetailsServicepassword:          That matches the one in the retrieved UserDetailsexpirationTime:    The date and time when the remember-me token expires, expressed in millisecondskey:               A private key to prevent modification of the remember-me token

因此,remember-me令牌仅在指定的时间段内有效,并且前提是用户名、密码和密钥不发生更改。值得注意的是,这有一个潜在的安全问题,因为捕获的remember-me令牌在令牌过期之前对任何用户代理都是可用的。这与摘要身份验证是相同的问题。如果主体意识到一个令牌已经被捕获,那么他们可以很容易地更改自己的密码,并立即使所有remember-me令牌失效。

持久化Token

需要配置数据源

数据库表

create table persistent_logins (username varchar(64) not null,                                series varchar(64) primary key,                                token varchar(64) not null,                                last_used timestamp not null)

相关接口和实现

TokenBasedRememberMeServices

此实现支持简单哈希令牌方法中描述的更简单的方法。TokenBasedRememberMeServices生成一个RememberMeAuthenticationToken,该token由RememberMeAuthenticationProvider处理。一个key在这个身份验证提供者和TokenBasedRememberMeServices之间共享。此外,TokenBasedRememberMeServices需要一个UserDetailsService,它可以从中检索用户名和密码,用于签名比较,并生成RememberMeAuthenticationToken来包含正确的GrantedAuthority 。应用程序应该提供某种注销命令,当用户请求时使cookie失效。TokenBasedRememberMeServices也实现了Spring Security的LogoutHandler接口,因此可以与LogoutFilter一起使用来自动清除cookie。

PersistentTokenBasedRememberMeServices

这个类可以以与TokenBasedRememberMeServices相同的方式使用,但是它还需要配置一个PersistentTokenRepository来存储令牌。有两种标准实现。

  • InMemoryTokenRepositoryImpl 内存
  • JdbcTokenRepositoryImpl 数据库

OpenID支持

Anonymous Authentication匿名认证

Pre-Authentication

有些情况下,您希望使用Spring Security进行授权,但是用户在访问应用程序之前已经通过某些外部系统的可靠身份验证。我们将这些情况称为“预先身份验证”场景。例如X.509、Siteminder和应用程序在其中运行的Java EE容器的身份验证。当使用预认证时,Spring Security必须

  • 识别发出请求的用户
  • 获取用户的权限。

具体细节将取决于外部身份验证机制。对于X.509,用户可以通过证书信息来标识,对于Siteminder,则可以通过HTTP请求头来标识。如果依赖容器身份验证,将通过调用传入HTTP请求的getUserPrincipal()方法来标识用户。在某些情况下,外部机制可能为用户提供角色/权限信息,但在其他情况下,权限必须从单独的来源获得,如UserDetailsService。

JAAS Provider

JAAS: Java Authentication and Authorization Service

Spring Security提供了一个能够将身份验证请求委托JAAS的包。

CAS 认证

JA-SIG在系统上产生一个企业范围的单点登录,称为CAS。与其他方法不同的是,JA-SIG的中央认证服务是开源的、被广泛使用、易于理解、平台独立并支持代理功能。Spring Security完全支持CAS,并提供了从Spring Security的单一应用程序部署到由企业范围的CAS服务器保护的多应用程序部署的简单迁移路径。

CAS参考资料https://www.apereo.org

Spring Security 中CAS认证参考资料 https://docs.spring.io/spring-security/site/docs/5.3.9.RELEASE/reference/html5/#servlet-cas

X.509认证

X.509证书身份验证最常用的用法是在使用SSL时验证服务器的身份,最常用的用法是在浏览器中使用HTTPS时。浏览器将自动检查服务器提供的证书是否已由它所维护的可信证书颁发机构之一颁发(即数字签名)。

参考资料 https://docs.spring.io/spring-security/site/docs/5.3.9.RELEASE/reference/html5/#servlet-x509

Run-As Authentication Replacement

AbstractSecurityInterceptor能够在安全对象回调阶段临时替换SecurityContextHolderSecurityContext中的Authentication对象。只有AuthenticationManagerAccessDecisionManager成功处理了原始的Authentication对象时才会发生这种情况。RunAsManager将指示应该在SecurityInterceptorCallback期间使用的替换Authentication对象(如果有的话)。

通过在安全对象回调阶段临时替换Authentication对象,安全调用将能够调用其他需要不同身份验证和授权凭证的对象。它还能够对特定的GrantedAuthority对象执行任何内部安全检查。因为Spring Security提供了许多helper类,它们基于SecurityContextHolder的内容自动配置远程协议,所以这些run-as替换在调用远程web服务时特别有用

处理logout

这部分参考我的另一篇文章

认证事件监听

参考

转载地址:https://console.blog.csdn.net/article/details/116464107 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Spring Security 之用户名/密码 认证
下一篇:Sprng Security 架构处理流程

发表评论

最新留言

感谢大佬
[***.8.128.20]2024年04月07日 10时34分30秒