新版Spring Security6.2案例 - Authentication用户名密码
创始人
2024-12-26 02:34:29
0

前言:

前面有翻译了新版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 登录表单。

  	 		Please Log In 	 	 		

Please Log In

Invalid username and password.
You have been logged out.

关于默认 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 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官网》

相关内容

热门资讯

透视曝光!hhpoker透视脚... 透视曝光!hhpoker透视脚本视频,hhpoker脚本(透视)好像有脚本(哔哩哔哩)1、破解器简单...
透视妙招!xpoker辅助,拱... 透视妙招!xpoker辅助,拱趴大菠萝辅助器最新更新内容介绍(辅助)总是一直总是有神器(哔哩哔哩)所...
7分钟妙计!传送屋app辅助脚... 7分钟妙计!传送屋app辅助脚本怎么设置密码,如何设置财神十三章的辅助功能(辅助)真是是有下载(哔哩...
透视练习!德普之星私人局辅助免... 透视练习!德普之星私人局辅助免费,德普之星app总是存在有开挂,3分钟教程(存在有挂)1、让任何用户...
透视揭幕!wpk辅助器是真的吗... 透视揭幕!wpk辅助器是真的吗,wpk辅助哪里买(透视)其实有神器(哔哩哔哩)1、免费辅助多个强度级...
透视烘培!德州真人透视脚本,欢... 透视烘培!德州真人透视脚本,欢乐茶馆修改器辅助(辅助)原来是真的有app(哔哩哔哩)小薇(辅助器软件...
第7分钟烘培!心悦踢透视辅助器... 第7分钟烘培!心悦踢透视辅助器免费,新老夫子较二八年(辅助)本来有挂下载(哔哩哔哩)1、第7分钟烘培...
透视方针!pokemmo辅助工... 透视方针!pokemmo辅助工具,WePoKer设置原来是有下载,第八分钟教程(有人有挂)1、pok...
透视辅助!德普辅助器怎么用,德... 透视辅助!德普辅助器怎么用,德扑圈透视(透视)好像是真的器(哔哩哔哩)是不是有人用挂微扑克wpk插件...
透视方式!智星菠萝可以辅助吗,... 透视方式!智星菠萝可以辅助吗,三哥玩透视辅助(辅助)竟然真的是有教程(哔哩哔哩)亲,关键说明,三哥玩...