新版Spring Security6.2案例 - Authentication用户名密码

前言:

前面有翻译了新版Spring Security6.2架构,包括总体架构,Authentication和Authorization,感兴趣可以直接点链接,这篇翻译官网给出的关于Authentication的Username/Password这页。

首先呢,官网就直接给出了基于用户名和密码的认证的代码,可以说是spring security的一个入门小案例,表单登录,输入用户名密码,和内存中的用户名密码匹配,如果匹配了就会成功登录。

Username/Password Authentication

验证用户的最常用方法之一是验证用户名和密码。Spring Security为使用用户名和密码进行身份验证提供了全面的支持。可以通过以下方式配置用户名密码认证

@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
			.authorizeHttpRequests((authorize) -> authorize
				.anyRequest().authenticated()
			)
			.httpBasic(Customizer.withDefaults())
			.formLogin(Customizer.withDefaults());

		return http.build();
	}

	@Bean
	public UserDetailsService userDetailsService() {
		UserDetails userDetails = User.withDefaultPasswordEncoder()
			.username("user")
			.password("password")
			.roles("USER")
			.build();

		return new InMemoryUserDetailsManager(userDetails);
	}

}

前面的配置会自动向 SecurityFilterChain 注册内存中 UserDetailsService,将DaoAuthenticationProvider 注册到默认的 AuthenticationManager,并启用表单登录和 HTTP 基本身份验证。

官网这边也列举了很多例子,我这边也都附上了超链接,因为前面代码是表单登录的,所以优先把超链接第一点,"我想了解表单登录如何工作"这节翻译了。

要了解更多关于usernamepassword身份验证的信息,请考虑以下用例:

  • 我想了解表单登录如何工作
  • 我想了解HTTP基本身份验证如何工作
  • 我想了解DaoAuthenticationProvider如何工作
  • 我想在内存中管理用户
  • 我想管理数据库中的用户
  • 我想在LDAP中管理用户
  • 我想发布一个用于自定义身份验证的AuthenticationManager bean
  • 我想自定义全局AuthenticationManager

表单登录的原理

Spring Security支持通过HTML表单提供用户名和密码。首先,我们看看如何将用户重定向到登录表单

上图基于 SecurityFilterChain 流程图。 

  1. 首先,用户向未授权的资源 (/private) 发出未经身份验证的请求。
  2. Spring Security 的 AuthorizationFilter 通过抛出 AccessDeniedException 来指示未经身份验证的请求被拒绝。
  3. 由于用户未经过身份验证,因此 ExceptionTranslationFilter 将启动“启动身份验证”,并使用配置的 AuthenticationEntryPoint 将重定向发送到登录页。在大多数情况下,AuthenticationEntryPoint 是 LoginUrlAuthenticationEntryPoint 的实例。
  4. 浏览器请求重定向到的登录页面。
  5. 应用程序中的某些内容必须呈现在登录页面。

当提交用户名和密码时,UsernamePasswordAuthenticationFilter对用户名和密码进行认证。UsernamePasswordAuthenticationFilter扩展了AbstractAuthenticationProcessingFilter,因此下面的图看起来应该非常相似。

该图建立在SecurityFilterChain图的基础上。

1.当用户提交其用户名和密码时,UsernamePasswordAuthenticationFilter 通过从 HttpServletRequest 实例中提取用户名和密码来创建 UsernamePasswordAuthenticationToken,UsernamePasswordAuthenticationToken是一种身份验证类型。

2.接下来,将UsernamePasswordAuthenticationToken传递到要进行身份验证的AuthenticationManager实例中。AuthenticationManager的细节取决于用户信息的存储方式。

3.如果身份验证失败,则定义为”失败“,并做如下:

        (1).清除SecurityContextHolder。

        (2).调用 RememberMeServices.loginFail。如果未配置“记住我”,则为空操作。请参阅 Javadoc 中的 RememberMeServices 接口。

        (3).调用AuthenticationFailureHandler。请参阅Javadoc中的AuthenticationFailureHandler类

4.如果身份验证成功,则显定义为”成功“,并做如下:

        (1).SessionAuthenticationStrategy收到新登录的通知。请参阅Javadoc中的SessionAuthenticationStrategy接口。

        (2).身份验证设置在securitycontexholder上。请参阅Javadoc中的SecurityContextPersistenceFilter类。

        (3).RememberMeServices。调用loginSuccess。如果记得我没有配置,这是一个no-op。请参阅Javadoc中的memormeservices接口。

        (4).ApplicationEventPublisher发布一个InteractiveAuthenticationSuccessEvent事件。

        (5).调用AuthenticationSuccessHandler。通常,这是一个SimpleUrlAuthenticationSuccessHandler,当我们重定向到登录页面时,它会重定向到由ExceptionTranslationFilter保存的请求。

默认情况下,Spring Security 表单登录处于启用状态。但是,一旦提供了任何基于 servlet 的配置,就必须显式提供基于表单的登录。以下示例显示了一个最小的显式 Java 配置:

public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		.formLogin(withDefaults());
	// ...
}

在前面的配置中,Spring Security 呈现默认登录页面。大多数生产应用程序都需要自定义登录表单。

以下配置演示了如何提供自定义登录表单。

ublic SecurityFilterChain filterChain(HttpSecurity http) {
	http
		.formLogin(form -> form
			.loginPage("/login")
			.permitAll()
		);
	// ...
}

在 Spring Security 配置中指定登录页面时,用户负责呈现页面。以下 Thymeleaf 模板生成符合 /login 登录页的 HTML 登录表单。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
	<head>
		<title>Please Log In</title>
	</head>
	<body>
		<h1>Please Log In</h1>
		<div th:if="${param.error}">
			Invalid username and password.</div>
		<div th:if="${param.logout}">
			You have been logged out.</div>
		<form th:action="@{/login}" method="post">
			<div>
			<input type="text" name="username" placeholder="Username"/>
			</div>
			<div>
			<input type="password" name="password" placeholder="Password"/>
			</div>
			<input type="submit" value="Log in" />
		</form>
	</body>
</html>

关于默认 HTML 表单,有几个关键点:

  • 表单应执行 post 到 /login。
  • 该表单需要包含一个 CSRF 令牌,该令牌由 Thymeleaf 自动包含。
  • 表单应在名为 username 的参数中指定用户名。
  • 表单应在名为 password 的参数中指定密码。
  • 如果找到名为 error 的 HTTP 参数,则表示用户未能提供有效的用户名或密码。
  • 如果找到名为 logout 的 HTTP 参数,则表示用户已成功注销。

许多用户只需要自定义登录页面即可。但是,如果需要,您可以使用其他配置自定义前面显示的所有内容。

如果您使用 Spring MVC,则需要一个将 GET /login 映射到我们创建的登录模板的控制器。以下示例显示了一个最小的 LoginController:

@Controller
class LoginController {
	@GetMapping("/login")
	String login() {
		return "login";
	}
}

最后在官网Username/Password这页中,还有描写关于自定义身份的authentication bean和全局authenticationManger,也就是上面超链接最后2点,先翻译出来,再后续博客中接着讲,本文可以着重看前面的表单登录即可

发布一个AuthenticationManager bean

一个相当常见的要求是发布 AuthenticationManager bean 以允许自定义身份验证,例如在 @Service 或 Spring MVC @Controller中。例如,您可能希望通过 REST API 而不是使用表单登录对用户进行身份验证。

@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
			.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/login").permitAll()
				.anyRequest().authenticated()
			);

		return http.build();
	}

	@Bean
	public AuthenticationManager authenticationManager(
			UserDetailsService userDetailsService,
			PasswordEncoder passwordEncoder) {
		DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
		authenticationProvider.setUserDetailsService(userDetailsService);
		authenticationProvider.setPasswordEncoder(passwordEncoder);

		return new ProviderManager(authenticationProvider);
	}

	@Bean
	public UserDetailsService userDetailsService() {
		UserDetails userDetails = User.withDefaultPasswordEncoder()
			.username("user")
			.password("password")
			.roles("USER")
			.build();

		return new InMemoryUserDetailsManager(userDetails);
	}

	@Bean
	public PasswordEncoder passwordEncoder() {
		return PasswordEncoderFactories.createDelegatingPasswordEncoder();
	}

}

有了上述配置,您就可以创建一个使用AuthenticationManager的@RestController,如下所示:

@RestController
public class LoginController {

	private final AuthenticationManager authenticationManager;

	public LoginController(AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}

	@PostMapping("/login")
	public ResponseEntity<Void> login(@RequestBody LoginRequest loginRequest) {
		Authentication authenticationRequest =
			UsernamePasswordAuthenticationToken.unauthenticated(loginRequest.username(), loginRequest.password());
		Authentication authenticationResponse =
			this.authenticationManager.authenticate(authenticationRequest);
		// ...
	}

	public record LoginRequest(String username, String password) {
	}

}

本例中,如果需要,您有责任将经过身份验证的用户保存在securitycontextrerepository中。例如,如果使用HttpSession在请求之间持久化SecurityContext,您可以使用httpessionsecuritycontextrepository。

自定义 AuthenticationManager

通常,Spring Security 在内部构建一个 AuthenticationManager,该管理器由 DaoAuthenticationProvider 组成,用于用户名/密码身份验证。在某些情况下,可能仍需要自定义 Spring Security 使用的 AuthenticationManager 实例。例如,您可能需要简单地为缓存用户禁用凭据擦除。您可以使用以下配置发布 AuthenticationManager:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
			.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/login").permitAll()
				.anyRequest().authenticated()
			)
			.httpBasic(Customizer.withDefaults())
			.formLogin(Customizer.withDefaults());

		return http.build();
	}

	@Bean
	public AuthenticationManager authenticationManager(
			UserDetailsService userDetailsService,
			PasswordEncoder passwordEncoder) {
		DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
		authenticationProvider.setUserDetailsService(userDetailsService);
		authenticationProvider.setPasswordEncoder(passwordEncoder);

		ProviderManager providerManager = new ProviderManager(authenticationProvider);
		providerManager.setEraseCredentialsAfterAuthentication(false);

		return providerManager;
	}

	@Bean
	public UserDetailsService userDetailsService() {
		UserDetails userDetails = User.withDefaultPasswordEncoder()
			.username("user")
			.password("password")
			.roles("USER")
			.build();

		return new InMemoryUserDetailsManager(userDetails);
	}

	@Bean
	public PasswordEncoder passwordEncoder() {
		return PasswordEncoderFactories.createDelegatingPasswordEncoder();
	}

}

或者,您可以利用用于构建 Spring Security 的全局 AuthenticationManager 的 AuthenticationManagerBuilder 作为 Bean 发布的事实。您可以按如下方式配置构建器:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		// ...
		return http.build();
	}

	@Bean
	public UserDetailsService userDetailsService() {
		// Return a UserDetailsService that caches users
		// ...
	}

	@Autowired
	public void configure(AuthenticationManagerBuilder builder) {
		builder.eraseCredentials(false);
	}

}

参考文献:

《spring boot官网》

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

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

相关文章

[Linux] LAMP架构

一、LAMP架构架构的概述 LAMP 架构是一种流行的 Web 应用程序架构&#xff0c;它的名称是由四个主要组件的首字母组成的&#xff1a; Linux&#xff08;操作系统&#xff09;&#xff1a; 作为操作系统&#xff0c;Linux 提供了服务器的基础。它负责处理硬件资源、文件系统管理…

医院污水处理设备远程监控超标报警解决方案

行业背景 近年来&#xff0c;我国医疗机构建设得到了巨大的发展。根据《2022年我国卫生健康事业发展统计公报》&#xff0c;2022年末&#xff0c;全国医疗卫生机构总数达1032918个。截至2022年10月&#xff0c;根据全国排污许可证管理信息平台&#xff0c;共有 13316家医院核发…

融合人脸识别、云计算、人工智能等技术的智慧校园管理系统源码

智慧电子班牌可以实现作业布置&#xff0c;评分以及留言反馈&#xff1b;还可以提高老师的工作效率&#xff1b;也可以关联走班排课系统&#xff0c;老师和学生可以实时查看课程信息&#xff0c;做好课前准备&#xff0c;家长也可以在软件上进行请假、查询等&#xff0c;老师可…

智能化配电房

智能化配电房是一种集成了先进技术和智能化设备的配电房&#xff0c;通过智能采集终端与通信设备&#xff0c;实时将电气参数、运行信息和环境数据传送至智慧电力物联网平台—电易云&#xff0c;对配电室进行数字化升级&#xff0c;对运维工作数字化升级&#xff0c;建设电力系…

初识GroovyShell

文章目录 前言一、GroovyShell二、maven三、解决方案四、关键代码4.1 数据库配置表(pg)4.2 入参4.3 分页查询 总结 前言 项目背景&#xff1a;查询多个表的数据列表和详情&#xff0c;但不想创建过多的po、dao、resp等项目文件。 一、GroovyShell Apache Groovy是一种强大的…

谈谈MYSQL主从复制原理

目录 概述 要点binlog日志 主从复制过程 总结 概述 MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。 MySQL 默认采用异步复制方式。从节点不用一直访问主服务器来更新自己的数据&#xff0c;数据的更新可以在远程连接上进行&#xff0…

HTTP 500错误:服务器内部错误,原因及解决方案

大家好&#xff0c;今天我们来聊聊一个常见的问题——HTTP 500错误&#xff0c;也就是服务器内部错误。这个错误就像是一个神秘的魔法&#xff0c;时不时地出现在你的网页上&#xff0c;让你的用户和你在一片懵逼中互相猜疑。 首先&#xff0c;我们来了解一下这个错误。HTTP 5…

LabVIEW在高铁温度与振动监测中的应用

​LabVIEW在高铁温度与振动监测中的应用 高速铁路的可靠性和安全性是现代铁路运输系统设计和运营的重中之重。LabVIEW软件作为一个多功能、可扩展的图形编程环境&#xff0c;提供了一个理想的平台&#xff0c;用于开发高铁监测系统&#xff0c;不仅监测实时数据&#xff0c;也…

数据常见的提取和筛选方法

平时对于一些不标准的数据&#xff0c;需要提取或者筛选其中的部分数据。本文主要分享一些常用的办法&#xff0c;同时也作为一个笔记的备份。 1. 正则表达式 正则表达式比较适合提取有明确类型的数据&#xff0c;比如字母&#xff0c;数字&#xff0c;汉字&#xff0c;日期等…

python自动化测试实战 —— WebDriver API的使用

软件测试专栏 感兴趣可看&#xff1a;软件测试专栏 自动化测试学习部分源码 python自动化测试相关知识&#xff1a; 【如何学习Python自动化测试】—— 自动化测试环境搭建 【如何学习python自动化测试】—— 浏览器驱动的安装 以及 如何更…

Python中的TesserOCR:文字识别的全方位指南

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 文字识别在图像处理领域中起到了至关重要的作用&#xff0c;而TesserOCR&#xff08;Tesseract OCR的Python封装&#xff09;为开发者提供了一个强大的工具&#xff0c;使得文字识别变得更加便捷。本文将通过详细…

MATLAB 最小二乘直线拟合方法二 (36)

MATLAB 最小二乘直线拟合方法二 (36) 一、算法介绍二、算法实现1.代码2.结果一、算法介绍 这里介绍另一种拟合直线点云的方法,更为简单方便,结果与前者一致,主要内容直接复制代码使用即可,原理简单看代码即可,下面是具体的实现和拟合结果展示 二、算法实现 1.代码 代…

死锁的概念

死锁&#xff08;Deadlock&#xff09;、饥饿&#xff08;Starvation&#xff09;和死循环&#xff08;Infinite Loop&#xff09;是计算机科学中与并发和并行处理相关的三个概念&#xff0c;它们描述了不同类型的问题和情况。 死锁&#xff08;Deadlock&#xff09;: 定义: 死…

纯前端使用XLSX导出excel表格

1 单个sheet page.js(页面中的导出方法) import { exportExcel } from ../../../utils/exportExcel.js; leadOut() {const arr [{ id: 1, name: 张三, age: 14, sex: 男 },{ id: 2, name: 李四, age: 15, sex: 女 },{ id: 3, name: 王五, age: 16, sex: 男 },];const allR…

全志V3s之U-Boot

1、安装交叉编译器&#xff1a; ARM交叉编译器的官网&#xff1a;交叉编译器 a、使用wget下载&#xff1a; wget https://releases.linaro.org/components/toolchain/binaries/latest/arm-linux-gnueabihf/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf.tar.xzb、解…

数据结构从入门到入土——初识泛型

目录 一&#xff0c;包装类 1.基本数据类型和对应的包装类 2.装箱和拆箱 3.自动装箱和自动拆箱 二&#xff0c;什么是泛型&#xff1f; 三&#xff0c;引出泛型 语法 四&#xff0c;泛型类的使用 1.语法 2.类型推导(Type Inference) 五&#xff0c;裸类型(Raw Type) …

Mybatis的foreach标签的使用以及参数的含义

Mybatis的foreach标签的使用以及参数的含义 语法格式&#xff1a; 属性说明&#xff1a; collection属性的注意点&#xff1a;

【UE5.1】套用小白人蓝图,让玩家控制MetaHuman移动

效果 步骤 1. 新建一个工程&#xff0c;创建Basic关卡&#xff0c;添加第三人称游戏资源到内容浏览器 2. 打开Quixel Bridge 选择高质量&#xff0c;然后添加创建好的MetaHuman到内容浏览器 启用所有缺失 立即重启 添加完毕后内容浏览器会多出“MetaGumans”文件夹&#xff0…

字符处理 C语言xdoj52

问题描述 从键盘输入一个字符&#xff0c;若为小写字母&#xff0c;则输出其对应的大写字母&#xff1b;若为大写字母&#xff0c;则输出对应的小写字母&#xff1b;其他字符原样输出。 输入说明 输入一个字符 输出说明 输出一个字符 输入样例 样例1输入 a 样例…

再回首感知损失在low-level上的应用

《Perceptual Losses for Real-Time Style Transfer and Super-Resolution》是李飞飞团队在2016年发表于ECCV的文章。我近几年的工作中&#xff0c;所训练的模型都离不开感知损失。不得不感慨&#xff0c;大佬之所以是大佬&#xff0c;就是因为他们开创性的工作很多年后依然为人…