拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 Spring Security:升级已弃用的WebSecurityConfigurerAdapter

Spring Security:升级已弃用的WebSecurityConfigurerAdapter

白鹭 - 2022-08-09 2651 0 2

一、概述

Spring Security 允许通过扩展WebSecurityConfigurerAdapter类为端点授权或身份验证管理器配置等特性定制HTTP 安全性。然而,从最近的版本开始,Spring 弃用了这种方法并鼓励基于组件的安全配置。

在本教程中,我们将看到一个示例,说明如何在Spring Boot 应用程序中替换此弃用并运行一些MVC 测试。

2. 没有WebSecurityConfigurerAdapter的Spring Security

我们通常会看到扩展WebSecurityConfigureAdapter类的Spring HTTP 安全配置类。

但是,从5.7.0-M2 版本开始,Spring 不赞成使用WebSecurityConfigureAdapter并建议在没有它的情况下创建配置

我们将使用内存中身份验证创建一个示例Spring Boot 应用程序来展示这种新型配置。

首先,让我们定义我们的配置类:

@EnableWebSecurity
 @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
 public class SecurityConfig {

 // config

 }

我们正在添加方法安全注释以启用基于不同角色的处理。

2.1。配置身份验证

使用WebSecurityConfigureAdapter,我们使用AuthenticationManagerBuilder来设置我们的身份验证上下文。

现在,如果我们想避免弃用,我们可以定义一个UserDetailsManagerUserDetailsService组件:

@Bean
 public UserDetailsService userDetailsService(BCryptPasswordEncoder bCryptPasswordEncoder) {
 InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
 manager.createUser(User.withUsername("user")
 .password(bCryptPasswordEncoder.encode("userPass"))
 .roles("USER")
 .build());
 manager.createUser(User.withUsername("admin")
 .password(bCryptPasswordEncoder.encode("adminPass"))
 .roles("USER", "ADMIN")
 .build());
 return manager;
 }

或者,给定我们的UserDetailService,我们甚至可以设置一个AuthenticationManager

@Bean
 public AuthenticationManager authManager(HttpSecurity http, BCryptPasswordEncoder bCryptPasswordEncoder, UserDetailService userDetailService)
 throws Exception {
 return http.getSharedObject(AuthenticationManagerBuilder.class)
 .userDetailsService(userDetailsService)
 .passwordEncoder(bCryptPasswordEncoder)
 .and()
 .build();
 }

同样,如果我们使用JDBC 或LDAP 身份验证,这将起作用。

2.2.配置 HTTP 安全性

更重要的是,如果我们想避免弃用HTTP 安全性,我们现在可以创建一个SecurityFilterChainbean。

例如,假设我们想根据角色保护端点,并留下一个匿名入口点仅用于登录。我们还将任何删除请求限制为管理员角色。我们将使用基本身份验证:

@Bean
 public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
 http.csrf()
 .disable()
 .authorizeRequests()
 .antMatchers(HttpMethod.DELETE)
 .hasRole("ADMIN")
 .antMatchers("/admin/**")
 .hasAnyRole("ADMIN")
 .antMatchers("/user/**")
 .hasAnyRole("USER", "ADMIN")
 .antMatchers("/login/**")
 .anonymous()
 .anyRequest()
 .authenticated()
 .and()
 .httpBasic()
 .and()
 .sessionManagement()
 .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

 return http.build();
 }

HTTP 安全将构建一个DefaultSecurityFilterChain对象来加载请求匹配器和过滤器。

2.3.配置网络安全

此外,对于Web 安全,我们现在可以使用回调接口WebSecurityCustomizer.

让我们添加一个调试级别并忽略一些路径,例如图像或脚本:

@Bean
 public WebSecurityCustomizer webSecurityCustomizer() {
 return (web) -> web.debug(securityDebug)
 .ignoring()
 .antMatchers("/css/**", "/js/**", "/img/**", "/lib/**", "/favicon.ico");
 }

3.端点控制器

让我们为我们的应用程序定义一个简单的REST 控制器类:

@RestController
 public class ResourceController {
 @GetMapping("/login")
 public String loginEndpoint() {
 return "Login!";
 }

 @GetMapping("/admin")
 public String adminEndpoint() {
 return "Admin!";
 }

 @GetMapping("/user")
 public String userEndpoint() {
 return "User!";
 }

 @GetMapping("/all")
 public String allRolesEndpoint() {
 return "All Roles!";
 }

 @DeleteMapping("/delete")
 public String deleteEndpoint(@RequestBody String s) {
 return "I am deleting " + s;
 }
 }

正如我们之前在定义HTTP 安全性时提到的,我们将添加一个任何人都可以访问的通用/login端点、管理员和用户的特定端点,以及一个不受角色保护但仍需要身份验证的/all端点。

4. 测试端点

让我们使用MVC 模拟将我们的新配置添加到Spring Boot Test 以测试我们的端点。

4.1。测试匿名用户

匿名用户可以访问/login端点。如果他们尝试访问其他内容,他们将未经授权(401):

@Test
 @WithAnonymousUser
 public void whenAnonymousAccessLogin_thenOk() throws Exception {
 mvc.perform(get("/login"))
 .andExpect(status().isOk());
 }

 @Test
 @WithAnonymousUser
 public void whenAnonymousAccessRestrictedEndpoint_thenIsUnauthorized() throws Exception {
 mvc.perform(get("/all"))
 .andExpect(status().isUnauthorized());
 }

此外,对于除/login之外的所有端点,我们总是需要身份验证,就像/all端点一样。

4.2.测试用户角色

用户角色可以访问通用端点以及我们为此角色授予的所有其他路径:

@Test
 @WithUserDetails()
 public void whenUserAccessUserSecuredEndpoint_thenOk() throws Exception {
 mvc.perform(get("/user"))
 .andExpect(status().isOk());
 }

 @Test
 @WithUserDetails()
 public void whenUserAccessRestrictedEndpoint_thenOk() throws Exception {
 mvc.perform(get("/all"))
 .andExpect(status().isOk());
 }

 @Test
 @WithUserDetails()
 public void whenUserAccessAdminSecuredEndpoint_thenIsForbidden() throws Exception {
 mvc.perform(get("/admin"))
 .andExpect(status().isForbidden());
 }

 @Test
 @WithUserDetails()
 public void whenUserAccessDeleteSecuredEndpoint_thenIsForbidden() throws Exception {
 mvc.perform(delete("/delete"))
 .andExpect(status().isForbidden());
 }

值得注意的是,如果用户角色尝试访问受管理员保护的端点,用户会收到“禁止”(403)错误。

相反,没有凭据的人(例如前面示例中的匿名用户)将收到“未经授权”错误(401)。

4.3.测试管理员角色

如我们所见,具有管理员角色的人可以访问任何端点:

@Test
 @WithUserDetails(value = "admin")
 public void whenAdminAccessUserEndpoint_thenOk() throws Exception {
 mvc.perform(get("/user"))
 .andExpect(status().isOk());
 }

 @Test
 @WithUserDetails(value = "admin")
 public void whenAdminAccessAdminSecuredEndpoint_thenIsOk() throws Exception {
 mvc.perform(get("/admin"))
 .andExpect(status().isOk());
 }

 @Test
 @WithUserDetails(value = "admin")
 public void whenAdminAccessDeleteSecuredEndpoint_thenIsOk() throws Exception {
 mvc.perform(delete("/delete").content("{}"))
 .andExpect(status().isOk());
 }

5. 结论

在本文中,我们了解了如何在不使用WebSecurityConfigureAdapter的情况下创建Spring Security 配置,并在创建用于身份验证、HTTP 安全和Web 安全的组件时替换它。


标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *