一、概述
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
来设置我们的身份验证上下文。
现在,如果我们想避免弃用,我们可以定义一个UserDetailsManager
或UserDetailsService
组件:
@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 安全性,我们现在可以创建一个SecurityFilterChain
bean。
例如,假设我们想根据角色保护端点,并留下一个匿名入口点仅用于登录。我们还将任何删除请求限制为管理员角色。我们将使用基本身份验证:
@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 评论