Spring Security 表单配置(二)

news2024/11/24 7:38:51

Spring Security 表单配置(二)

  • 架构
  • 认证过滤器
  • 认证成功
  • 认证失败

架构

Spring Security的整体架构,官网文档有介绍:https://docs.spring.io/spring-security/reference/5.7/servlet/architecture.html

友情提示:可以使用Edge浏览器打开,翻译一下,帮助理解,英文阅读能力好的话忽略此提示。

在Spring Security的过滤器中有一套过滤器链,官网把他们按照顺序列出来了

ForceEagerSessionCreationFilter
ChannelProcessingFilter
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CorsFilter
CsrfFilter
LogoutFilter
OAuth2AuthorizationRequestRedirectFilter
Saml2WebSsoAuthenticationRequestFilter
X509AuthenticationFilter
AbstractPreAuthenticatedProcessingFilter
CasAuthenticationFilter
OAuth2LoginAuthenticationFilter
Saml2WebSsoAuthenticationFilter
UsernamePasswordAuthenticationFilter
OpenIDAuthenticationFilter
DefaultLoginPageGeneratingFilter
DefaultLogoutPageGeneratingFilter
ConcurrentSessionFilter
DigestAuthenticationFilter
BearerTokenAuthenticationFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
JaasApiIntegrationFilter
RememberMeAuthenticationFilter
AnonymousAuthenticationFilter
OAuth2AuthorizationCodeGrantFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
SwitchUserFilter

这些Filter的顺序很重要,上面排列的顺序也是他们调用的顺序。
其中

UsernamePasswordAuthenticationFilter

就是 使用用户名和密码认证时要通过的一个过滤器

认证过滤器

先看一下 UsernamePasswordAuthenticationFilter 这个类的方法结构
UsernamePasswordAuthenticationFilter

其中的 attemptAuthentication 方法就是认证逻辑

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
		if (this.postOnly && !request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
		}
		String username = obtainUsername(request);
		username = (username != null) ? username.trim() : "";
		String password = obtainPassword(request);
		password = (password != null) ? password : "";
		UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
				password);
		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);
		return this.getAuthenticationManager().authenticate(authRequest);
	}

在之前的配置中,就有涉及这个地方的配置,比如登录的url、请求方法、用户名的参数名、密码的参数名。
这里会从request获取对应的用户名和密码,然后构建一个未认证的UsernamePasswordAuthentiactionToken ,最后一步进行认证。
这个认证逻辑也是有套路的,通过ProviderManager进行认证,自身拿不到认证结果就从parent那里拿,一层层往上委托认证,最后委托到DaoAuthenticationProvider,从我们自定义的UserDetailsService中获取认证对象,至于我们的UserDetailsService何时注入到这个对象中,那就是另一个故事了,可以在set方法里面打一个断点,启动时就可以看到方法栈,看到类构建过程,这里就不看了。

认证成功

当认证成功,会回到 AbstractPreAuthenticatedProcessingFilter 的 successfulAuthentication 方法
设置身份上下文,触发认证成功事件,调用成功重定向处理器

认证成功后处理逻辑
认证成功重定向url

可以看到认证成功重定向url就是之前我们设置的。
当然Spring Security的配置方式很多,配置组合也很多,这只是其中一种。

认证失败

ProviderManager的authenticate方法

@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		// ... 省略一大堆认证逻辑
		if (result == null && this.parent != null) {
			// Allow the parent to try.
			try {
				parentResult = this.parent.authenticate(authentication);
				result = parentResult;
			}
			catch (ProviderNotFoundException ex) {
				// ignore as we will throw below if no other exception occurred prior to
				// calling parent and the parent
				// may throw ProviderNotFound even though a provider in the child already
				// handled the request
			}
			catch (AuthenticationException ex) {
				parentException = ex;
				lastException = ex;
			}
		}
		if (result != null) {
			if (this.eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
				// Authentication is complete. Remove credentials and other secret data
				// from authentication
				((CredentialsContainer) result).eraseCredentials();
			}
			// If the parent AuthenticationManager was attempted and successful then it
			// will publish an AuthenticationSuccessEvent
			// This check prevents a duplicate AuthenticationSuccessEvent if the parent
			// AuthenticationManager already published it
			if (parentResult == null) {
				this.eventPublisher.publishAuthenticationSuccess(result);
			}

			return result;
		}

		// Parent was null, or didn't authenticate (or throw an exception).
		if (lastException == null) {
			lastException = new ProviderNotFoundException(this.messages.getMessage("ProviderManager.providerNotFound",
					new Object[] { toTest.getName() }, "No AuthenticationProvider found for {0}"));
		}
		// If the parent AuthenticationManager was attempted and failed then it will
		// publish an AbstractAuthenticationFailureEvent
		// This check prevents a duplicate AbstractAuthenticationFailureEvent if the
		// parent AuthenticationManager already published it
		if (parentException == null) {
			prepareException(lastException, authentication);
		}
		throw lastException;
	}

如果没有拿到认证结果,而且还有parent,向上委托认证,单亲委托
一直往上找,找到老祖宗还没拿到认证结果,而且没有异常产生
那么就会产生一个异常ProviderNotFoundException

如果parent没有异常,那就发出认证失败事件
最终会抛出lastException异常

在认证过程中也会抛出异常,毕竟常见的BadCredentialsException
DaoAuthenticationProvider中additionalAuthenticationChecks方法会抛出

protected void additionalAuthenticationChecks(UserDetails userDetails,
			UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
		if (authentication.getCredentials() == null) {
			this.logger.debug("Failed to authenticate since no credentials provided");
			throw new BadCredentialsException(this.messages
					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
		}
		String presentedPassword = authentication.getCredentials().toString();
		if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
			this.logger.debug("Failed to authenticate since password does not match stored value");
			throw new BadCredentialsException(this.messages
					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
		}
	}

最后赋值给lastException,抛出到上层,到异常处理器。
具体逻辑在 AbstractAuthenticationProcessingFilter 的 doFilter方法中的异常catch块
最终调用了 unsuccessfulAuthentication 方法

protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException failed) throws IOException, ServletException {
		SecurityContextHolder.clearContext();
		this.logger.trace("Failed to process authentication request", failed);
		this.logger.trace("Cleared SecurityContextHolder");
		this.logger.trace("Handling authentication failure");
		this.rememberMeServices.loginFail(request, response);
		this.failureHandler.onAuthenticationFailure(request, response, failed);
	}

重定向的url也是之前配置的。

这里的成功和失败的执行逻辑和官网的逻辑流程图吻合。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

极客时间学习笔记:03芯片分类

芯片与集成电路的区别? 芯片肯定不全是集成电路。芯片里面,大约只有 80% 属于集成电路,其余的都是光电器件、传感器和分立器件,行业内把这些器件称为 O-S-D(Optoelectronic, Sensor, Discrete)。 下面这张…

SpringBoot 2.7.7入门案例

SpringBoot技术 文章目录SpringBoot技术SpringBoot介绍SpringBoot入门总结SpringBoot介绍 SpringBoot是为了简化搭建Spring项目过程而和开发的框架,Spring本身也是简化开发的框架技术。 可以想想SpringMVC项目(整合SSM)的开发过程&#xff…

【国信长天蓝桥杯】CT117E-M4 嵌入式开发板准备篇 ①开发环境搭建,Keil及STM32CubeMX的下载安装

摘要 本文章基于国信长天 CT117E-M4 嵌入式开发板,讲解了竞赛开发环境的搭建,Keil及STM32CubeMX软件的安装方法,祝各位同学蓝桥杯电子比赛取得好成绩! 软件下载 在蓝桥杯的嵌入式比赛中,主要用到两个软件,分别是代…

易烊千玺小网站短信验证码(小行星编号)发送和验证的实现

每次进入小网站都能看到小小的变化,反观易程序员背后维护的艰辛哈哈哈哈哈哈从此就多了一个目标:one day做出和易烊千玺一样牛的小网站这里面多多的知识点都是我目前都没有学会的(明明都实训了。。页面设计 各种小图标动态效果 网站域名申请 …

【人工智能】观看人工智能 (AI) 入门课程,一起来看看都讲了什么

作者:小5聊 简介:一只喜欢全栈方向的程序员,欢迎咨询,尽绵薄之力答疑解惑 公众号:有趣小馆,一个有趣的关键词回复互动功能 1、课程介绍 1)讨论什么是 AI 及其重要性 2)简要介绍机器学…

MEmu Android Emulator

MEmu Android Emulator是一款专门用于游戏的软件模拟器。你可以从很多方面享受使用MEmu类软件的乐趣,让某人可以直接在计算机上安装它们。您不需要配置复杂的设置,只需安装它们即可。 您可以通过单击右侧的APK按钮轻松安装Andrew游戏。你想安装的APK游戏…

OPPO软件商店APP侵权投诉流程

目录一、官方指引二、侵权投诉流程1.侵权受理流程图2.受理渠道3.权利人侵权投诉通知邮件一、官方指引 https://open.oppomobile.com/new/developmentDoc/info?id10826 二、侵权投诉流程 1.侵权受理流程图 2.受理渠道 侵权处理邮箱:iprheytap.com 侵权处理抄送邮…

一,Spring入门

1 Spring简介 Spring是一个轻量级的JavaEE应用框架,对比EJB(Enterprise Java Beans)技术是官方制定的重量级的JavaEE解决方案。EJB的重的表现:编码必须实现EJB内置的组件、必须部署在支持EJB的服务器中才能运行测试。EJB有很强的侵入性&…

ansible作业五

1、jinjia2模板 hosts.j2,内容如下(主机名和ip地址使用变量): Welcome to 主机名 !(比如servera.lab.example.com) My ip is ip地址. 要求在所有受管主机生成文件:/etc/welcome.txt。 2、角色部分 根据下列…

【Java|golang】2283. 判断一个数的数字计数是否等于数位的值

给你一个下标从 0 开始长度为 n 的字符串 num &#xff0c;它只包含数字。 如果对于 每个 0 < i < n 的下标 i &#xff0c;都满足数位 i 在 num 中出现了 num[i]次&#xff0c;那么请你返回 true &#xff0c;否则返回 false 。 示例 1&#xff1a; 输入&#xff1a;…

EXCEL的几个取整函数对比,int() round() ceiling() ceiling.math()等

1目标 我们处理EXCEL数据经常要遇到以下的需求 取整取倍数按任意数取倍数2 简单取整函数 int() int()只能最简单取整&#xff0c;无任何参数3 round() 四舍五入取整函数 & 整数位取整美化 round() roundup() rounddown() roundup() 和 rounddown() 除了向上和向下取整…

【树莓派4B】搭建HomeAssistant服务端

前言 发挥树莓派的剩余价值&#xff0c;看到知乎有大神利用siri语音控制小米生态的智能家居&#xff0c;他就是利用HA实现的&#xff0c;HA打通不同品牌智能硬件的生态壁垒&#xff0c;而且还是开源&#xff0c;而我刚好手里有一块闲置的树莓派&#xff08;斜眼笑&#xff09;…

【Linux】Linux调试器——gdb的使用以及一些指令

gdb的使用1.背景2.使用3.相关指令1.背景 程序的发布方式有两种&#xff0c;debug模式和release模式 Linux gcc/g出来的二进制程序&#xff0c;默认是release模式 要使用gdb调试&#xff0c;必须在源代码生成二进制程序的时候, 加上 -g 选项 2.使用 使用前先确保自己的Linux上有…

MongoDB的行转列查询

项目组数据需求&#xff0c;需要将Mongo库中的列按日期分组转成行的格式进行显示。Mongo群里问了下&#xff0c;群里热心的大佬小徐 同学果断出手相助&#xff0c;顺利解决了数据问题。现将内容总结梳理如下&#xff0c;帮助有需要的其他同学 表结构 建表语句 db.class.inse…

OSCP_vulnhub digitalworld.local: DEVELOPMENT

DIGITALWORLD.LOCAL: DEVELOPMENT安装&环境下载Description攻击寻找受害主机及端口服务nmap就提示了ctrl u的内容&#xff0c;意思是有隐藏目录搜索slogin_lib.inc.php site:exploit-db.comubantu系统&#xff0c;4.15.0 查找版本漏洞第二种vim sudo提权第三种nano sudo提权…

【前端修炼场】— table 表格的构建

此文为【前端修炼场】第七篇&#xff0c;上一篇文章链接&#xff1a;超链接 文章目录前言一、table 表格的引入二、table 表格属性2.1 边框( border )2.2 宽度( width )2.3 高度( height )2.4 水平对齐( align"left 或 right 或 center )2.5 单元格间距( cellspacing)2.6 …

极客时间学习笔记:04芯片-设计之路

其实一颗芯片项目就是一个标准的产品项目&#xff0c;项目的起点是市场需求分析&#xff0c;接着是设计和制造&#xff0c;如果产品成功完成了商业落地&#xff0c;那么就可以开启下一代产品的迭代升级新周期了。 如果只看芯片设计&#xff0c;它主要包含需求分析、架构设计、逻…

基于Openl启智平台如何提交代码至远程仓库

基于Openl启智平台如何提交代码至远程仓库Openl启智简介快速创建项目克隆项目到本地提交和更新文件Openl启智简介 面向新一代人工智能开源共性技术&#xff0c;面向AI领域的一站式协同开发环境&#xff0c;提供集代码开发环境&#xff0c;数据管理、模型调试、推理和评测为一体…

【Linux】常用基本指令(始)

文章目录&#x1f3aa; Linux下基本指令1.1 &#x1f680; 登录相关指令1.2 &#x1f680; ls1.3 &#x1f680; pwd1.4 &#x1f680; cd1.5 &#x1f680; touch1.6 &#x1f680;mkdir1.7 &#x1f680;rmdir && rm1.8 &#x1f680;man1.9 &#x1f680;cp2.0 &…

windows环境使用PHPStudy安装Redis

windows环境使用PHPStudy安装Redis 目录 安装Redis 开启php redis扩展 查看php扩展 启动redis 连接测试 总结 安装Redis 从软件管理中找到redis&#xff0c;点击安装 开启php redis扩展 选择相应网站管理 > php扩展> redis 查看是否勾选&#xff0c;如果未勾…