新版Spring Security6.2架构 (二) - Authentication

前言:

书接上文,继续官网的个人翻译和个人理解,有不对的请见谅。第一个篇博客中写到Sevlet appliation的总体架构,本博客是写Sevlet appliation中Authentication的架构,在后面第三篇博客将会写到新版spring security如何通过数据库进行认证,对这篇的一个实战。

Authentication 

Spring Security 为身份验证提供了全面的支持。首先讨论整体的 Servlet Authentication体系结构。

Authentication认证机制

提供了多种认证机制:

  • Username and Password - 用户名和密码的认证机制

  • OAuth 2.0 Login - 可以使用Open ID connect OAuth 2.0 登录 和非标准OA 2.0登录(如GitHub)

  • SAML 2.0 Login - SAML 2.0 登录

  • Central Authentication Server (CAS) - Central Authentication Server (CAS) 中心认证服务器支持

  • Remember Me - how to remember a user past session expiration 如何记住用户之前会话过期的信息

  • JAAS Authentication - 使用JAAS进行认证

  • Pre-Authentication Scenarios - 使用外部机制(如 SiteMinder 或 Java EE 安全性)进行身份验证,但仍使用 Spring Security 进行授权和防止常见漏洞。

  • X509 Authentication - X509 认证

Servlet 认证架构

Servlet Security的扩展。下图描述 Servlet 身份验证中使用的 Spring Security 的主要架构组件。如果需要具体的流程来解释这些部分如何组合在一起,请查看特定于身份验证机制的部分。

这边有许多名词解释:

  • SecurityContextHolder - SecurityContextHolder 是 Spring Security 存储身份验证人员详细信息的位置。
  • SecurityContext - 从 SecurityContextHolder 获取,包含当前经过身份验证的用户的身份验证信息。
  • Authentication - 可以是 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:
 

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

SecurityContextHolder.setContext(context); //3

1.首先创建一个空的 SecurityContext。应该创建一个新的 SecurityContext 实例,而不是使用 SecurityContextHolder.getContext().setAuthentication(authentication),以避免跨多个线程的争用条件。

2.接下来,创建一个新的 Authentication 对象。Spring Security 不关心在 SecurityContext 上设置了什幺类型的 Authentication 实现。这里,使用 TestingAuthenticationToken,因为它非常简单。实际上项目最常见是 UsernamePasswordAuthenticationToken(userDetails, password, authorities),就是前端发过来账号密码认证。

3.最后,我们在 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();

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

某些应用进程并不完全适合使用 ThreadLocal,因为它们使用线程的特定方式。例如,Swing 客户端可能希望 Java 虚拟机中的所有线程都使用相同的安全上下文。您可以使用启动时的策略配置 SecurityContextHolder,以指定您希望如何存储上下文。对于独立应用进程,您将使用SecurityContextHolder.MODE_GLOBAL策略。其他应用进程可能希望由安全线程生成的线程也采用相同的安全标识。您可以通过使用 SecurityContextHolder.MODE_INHERITABLETHREADLOCAL 来实现此目的。您可以通过两种方式更改默认SecurityContextHolder.MODE_THREADLOCAL模式。第一种是设置系统属性。第二种是在 SecurityContextHolder 上调用静态方法。大多数应用进程不需要更改默认值。但是,如果您这样做,请查看 SecurityContextHolder 的 JavaDoc 以了解更多信息。

SecurityContext

从SecurityContextHolder获取,存储Authentication的对象。

Authentication

Authentication 接口在 Spring Security 中有两个主要用途:

  • AuthenticationManager 的输入,用于提供用户提供的用于进行身份验证的凭据。在此方案中使用时,isAuthenticated() 返回 false。
  • 表示当前经过身份验证的用户。可以从 SecurityContext 获取当前的身份验证。

Authentication包含:

  • principal:标识用户。使用用户名/密码进行身份验证时,这通常是 UserDetails 的实例。
  • credentials:通常是密码。在许多情况下,在用户通过身份验证后会清除此信息,以确保它不会泄露。
  • authorities:GrantedAuthority 实例是授予用户的高级权限。两个示例是角色和作用域。

GrantedAuthority

 GrantedAuthority 实例是授予用户的高级权限。2个例子就是:角色和作用域。

可以从 Authentication.getAuthorities()方法获取 GrantedAuthority 实例。此方法提供 GrantedAuthority 对象的集合。毫不奇怪,GrantedAuthority 是授予委托人的权限。这些权力通常是“角色”,例如ROLE_ADMINISTRATOR或ROLE_HR_SUPERVISOR。稍后将针对 Web 授权、方法授权和域对象授权配置这些角色。Spring Security 的其他部分会解析这些权限,并将预期情况展示出来。使用基于用户名/密码的身份验证时,GrantedAuthority 实例通常由 UserDetailsService 加载。

通常,GrantedAuthority 对象是应用进程范围的权限。它们不特定于给定的域对象。因此,您不太可能使用 GrantedAuthority 来表示对 Employee 对象编号 54 的权限,因为如果有数千个这样的权限,您将很快耗尽内存(或者至少会导致应用进程需要很长时间才能对用户进行身份验证)。当然,Spring Security 是专门为处理这一常见需求而设计的,但您应该为此目的使用项目的域对象安全功能。

AuthenticationManager

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

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

ProviderManager

ProviderManager 是最常用的 AuthenticationManager 实现。ProviderManager 委托给 AuthenticationProvider 实例的 List。每个 AuthenticationProvider 都有机会指示身份验证应成功、失败,或指示它无法做出决定并允许下游 AuthenticationProvider 做出决定。如果配置的所有 AuthenticationProvider 实例都无法进行身份验证,则身份验证将失败,并出现 ProviderNotFoundException,这是一个特殊的 AuthenticationException,指示 ProviderManager 未配置为支持传递到其中的身份验证类型。

 

实际上,每个 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 属性。请参阅 Javadoc 中 的 Javadoc 类。

AuthenticationProvider

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

Request Credentials with AuthenticationEntryPoint

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

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

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

AbstractAuthenticationProcessingFilter

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

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

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

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

3.如果身份验证失败,则失败。

  • SecurityContextHolder 被清除。
  • RememberMeServices.loginFail 被调用。如果未配置“记住我”,则此操作无效。请参阅 Rememberme 包。
  • 调用 AuthenticationFailureHandler。请参阅 AuthenticationFailureHandler 接口。

4.如果身份验证成功,则成功。

  • SessionAuthenticationStrategy 收到新登录的通知。请参阅 SessionAuthenticationStrategy 接口。
  • 身份验证设置在 SecurityContextHolder 上。稍后,如果需要保存 SecurityContext 以便可以在将来的请求中自动设置它,则必须显式调用 SecurityContextRepository#saveContext。请参阅 SecurityContextHolderFilter 类。
  • RememberMeServices.loginSuccess 被调用。如果未配置“记住我”,则此操作无效。请参阅 Rememberme 包。
  • ApplicationEventPublisher 发布 InteractiveAuthenticationSuccessEvent。
  • 调用 AuthenticationSuccessHandler。请参阅 AuthenticationSuccessHandler 接口。

参考文献

《Spring boot 官网》 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/239263.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IO流(一)

目录 一.关于IO流 二.字节流 1.FIleOutputStream&#xff08;字节输出流&#xff09; 1.书写步骤&#xff1a; 1.创建字节输出流对象 2.写数据 3.释放资源 2.书写数据的三种方式 3.换行写入数据&#xff1a; 4.续写 2.FileInputStream&#xff08;字节输入流&#xf…

【算法-字符串3】听说KMP很难?进来看这篇:实现strstr(),查找子串

今天&#xff0c;带来KMP算法的讲解。文中不足错漏之处望请斧正&#xff01; 理论基础点这里 今天我们来实现strstr()。 题意转化 在一个字符串mainStr中找另一个字符串subStr。 解决思路 两指针i和j分别在mainStr和subStr中拿取字符尝试匹配 匹配&#xff1a;继续不匹配&…

HTML实现页面

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>工商银行电子汇款单</title> </head> &…

主机访问Android模拟器网络服务方法

0x00 背景 因为公司的一个手机app的开发需求&#xff0c;要尝试链接手机开启的web服务。于是在Android Studio的Android模拟器上尝试连接&#xff0c;发现谷歌给模拟器做了网络限制&#xff0c;不能直接连接。当然这个限制似乎从很久以前就存在了。一直没有注意到。 0x01 And…

回顾【数学基础】找出断层,继续前进, 使用chatGPT学习并解决实际问题:微积分

已经学过的算术、代数、几何。跳过。 从微积分开始 想象一下&#xff0c;你在画一条曲线&#xff0c;或者在一个大草地上奔跑。微积分就是一种数学工具&#xff0c;帮助我们了解这条曲线的形状&#xff0c;或者你奔跑的方式。 微分&#xff08;就像研究曲线上的每一小点&…

SQL基础理论篇(十一):事务隔离

文章目录 简介事务并发时的常见异常什么是脏读&#xff1f;什么是不可重复读&#xff1f;什么是幻读&#xff1f; 事务的常用隔离级别参考文献 简介 之前我们讲过事务的四大特性&#xff0c;即ACID&#xff0c;分别是原子性、一致性、隔离性和持久性。隔离性就是事务的基本特性…

ROBdispatch stage

ROB会跟踪所有pipeline中的指令的状态&#xff1b;一旦ROB中&#xff0c;header指的entry complete了&#xff0c;则该指令可以commit,其architectural state属于visible了&#xff1b;如果header instruction 发生了异常&#xff0c;pipleine需要flush, 在该exception instruc…

Python接口自动化测试 —— Requests库学习

安装&#xff1a; pip install requests 例子&#xff1a; import requests r requests.get(http://www.baidu.com) print r.status_code print type(r) print r.cookies运行程序&#xff0c;得到结果&#xff1a; 运行程序&#xff0c;得到结果&#xff1a; 200 <…

Leetcode—2963.统计好分割方案的数目【困难】

2023每日刷题&#xff08;五十七&#xff09; Leetcode—2963.统计好分割方案的数目 算法思想 参考灵神思路 实现代码 class Solution { public:long long mod 1e97;long long pow(long long x, int cnt) {if(cnt 0) {return 1;}if(cnt 1) {return x % mod;}long long …

css处理 纯英文数据不换行问题 - word-break、word-wrap

问题图 解决 添加 css 样式 word-break: break-all;补充 还有一个 word-wrap 样式&#xff0c;可以看下 参考 &#xff1a; word-wrap: normal 只在允许的断字点换行&#xff08;浏览器保持默认处理&#xff09;。word-wrap: break-word 在长单词或 URL 地址内部进行换行。

书-选择排序法P156

#include<stdio.h> int main(){int b[5]{8,2,6,3,7};int i , j ,k ;for(i0;i<4;i){for(ji1;j<5;j)if(b[i]<b[j]){kb[i];b[i]b[j];b[j]k;} }for(i0;i<5;i)printf("%d ",b[i]); return 0; }选择排序&#xff1a;就是自己跟下一个比较&#xff0c;然后…

Android studio 无法查看源码

Android studio 查看源码时提示 Decompiled .class file,bytecode version:52.0(java 8) 1、检查 buildToolsVersion 2、检查相关资源文件

SPRD Android 13 下拉状态栏菜单添加静音快捷键简单记录

SPRD Android 13 下拉状态栏菜单添加静音快捷键简单记录 需要修改文件具体修改补丁吐槽需要修改文件 frameworks/base/packages/SystemUI/res/values/config.xml frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java frameworks/base…

1844_高边驱动以及低边驱动的选择

Grey 全部学习内容汇总&#xff1a;GitHub - GreyZhang/g_hardware_basic: You should learn some hardware design knowledge in case hardware engineer would ask you to prove your software is right when their hardware design is wrong! 1844_高边驱动以及低边驱动的…

mmpi量表在各企事业单位 入职体检中的应用

mmpi量表主要应用在医院精神科门诊中&#xff0c;用来检测筛查精神类疾病&#xff0c;比如&#xff1a;焦虑抑郁&#xff0c;疑病妄想强迫性、精神分裂、精神病态、社会内向性、癔症&#xff0c;精神衰弱&#xff0c;躁狂等等。 民航&#xff0c;司法&#xff0c;军警&#xf…

创建第一个SpringBoot项目

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 循序渐进学SpringBoot ✨特色专栏&…

点评项目——好友关注模块

2023.12.12 本章实现好友关注模块&#xff0c;包含以下功能的实现&#xff1a;关注与取关、共同关注、关注推送。 关注与取关 当点击某个用户的主页时&#xff0c;会调用如下接口&#xff1a; 该接口是用来判断是否已经关注该用户&#xff0c;最后一个参数是该用户的i…

1,使用IDLE开启我们第一个Python程序

前面我们已经安装好了Python&#xff0c;安装了Python后&#xff0c;他会自动帮我们安装一个IDLE。IDLE是一个Python自带的非常简洁的集成开发环境&#xff08;IDE&#xff09;。他是一个Python Shell&#xff0c;我们可以利用Python Shell与Python交互。下面我们就利用IDLE开发…

如何学习网络安全

我们应该怎么学习网络安全 首先&#xff0c;必须&#xff08;时刻&#xff09;意识到你是在学习一门可以说是最难的课程&#xff0c;是网络专业领域的顶尖课程&#xff0c;不是什么人、随随便便就能学好的。不然&#xff0c;大家都是黑客&#xff0c;也就没有黑客和网络安全的概…

【玩转TableAgent数据智能分析】TableAgent全功能详解及多领域数据分析实践(中)不同领域数据分析实践

3 电影点评数据分析实践 利用本身自带的电影点评数据&#xff0c;来具体看一下TableAgent的分析能力&#xff0c;选择电影点评数据&#xff0c;智能体会自动导入该数据DMSC20000.csv&#xff0c;大小为3.3 MB。在数据信息展示区&#xff0c;就会显示出该数据&#xff0c;并提供…