我已将 Spring Boot 项目升级到 Spring Boot 3。
我还更新了 WebSecurityConfig,现在看起来像这样:
// imports...
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class CustomWebSecurityConfig {
final UserDetailsServiceImpl userDetailsService;
private final AuthEntryPointJwt unauthorizedHandler;
private final PasswordEncoder passwordEncoder;
@Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder);
return authProvider;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
return authConfig.getAuthenticationManager();
}
/**
* Sets up a chain of antmatchers specifying what permissions and roles have access to which resources.
*
* @param http Injected HttpSecurity object
* @return Chain of Security filters
* @throws Exception Currently throws general exception
*/
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
// https://stackoverflow.com/questions/74447778/spring-security-in-spring-boot-3
.authorizeHttpRequests(requests -> requests.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/test/**").permitAll()
.requestMatchers("/").permitAll()
.requestMatchers("/index.html").permitAll()
.requestMatchers("/favicon.ico").permitAll()
.requestMatchers("/main.js").permitAll()
.requestMatchers("/polyfills.js").permitAll()
.requestMatchers("/runtime.js").permitAll()
.requestMatchers("/styles.css").permitAll()
.requestMatchers("/vendor.css").permitAll()
.requestMatchers("/assets/**").permitAll()
.requestMatchers("/error").permitAll()
.requestMatchers("/**").permitAll()
.anyRequest().authenticated());
http.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authenticationProvider(authenticationProvider());
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
这是带有 @PreAuthorize 的示例端点:
// imports...
@RestController
@RequestMapping("/api/test")
public class TestController {
@GetMapping("/all")
public String allAccess() {
return "Public Content.";
}
@GetMapping("/user")
@PreAuthorize("hasRole('USER') or hasRole('MODERATOR') or hasRole('ADMIN')")
public String userAccess() {
return "User Content.";
}
@GetMapping("/mod")
@PreAuthorize("hasRole('MODERATOR')")
public String moderatorAccess() {
return "Moderator Board.";
}
@GetMapping("/admin")
@PreAuthorize("hasRole('ADMIN')")
public String adminAccess() {
return "Admin Board.";
}
}
我为此用例编写的测试部分失败,因为登录用户可以访问所有端点,但默认情况下仅具有“USER”角色。 这 2 个测试失败:
@Test
@DisplayName("Give user no token and forbid access")
@WithMockUser(roles = "USER")
void givenUserToken_whenGetSecureRequest_thenForbidden() throws Exception {
mockMvc.perform(get("/api/test/mod"))
.andExpect(status().isForbidden());
}
@Test
@DisplayName("Give user no token and forbid access v.2")
@WithMockUser(roles = "USER")
void givenUserToken_whenGetSecureRequest_thenForbidden2() throws Exception {
mockMvc.perform(get("/api/test/admin"))
.andExpect(status().isForbidden());
}
我读过一些有关@EnableMethodSecurity的内容,但我还没有找到使用它并修复@PreAuthorize不起作用的方法
根据文档:
启用方法安全性
在 Spring Security 5.6 中,我们可以使用以下命令启用基于注释的安全性 任何 @Configuration 实例上的 @EnableMethodSecurity 注释。
只需将此注释添加到您的
@Configuration
类之上,它就应该可以工作。
Example:
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
).httpBasic(withDefaults());
return http.build();
}
}
这在很多方面改进了@EnableGlobalMethodSecurity。 @EnableMethodSecurity:
Uses the simplified AuthorizationManager API instead of metadata sources, config attributes, decision managers, and voters. This simplifies reuse and customization.
Favors direct bean-based configuration, instead of requiring extending GlobalMethodSecurityConfiguration to customize beans
Is built using native Spring AOP, removing abstractions and allowing you to use Spring AOP building blocks to customize
Checks for conflicting annotations to ensure an unambiguous security configuration
Complies with JSR-250
Enables @PreAuthorize, @PostAuthorize, @PreFilter, and @PostFilter by default
https://docs.spring.io/spring-security/reference/servlet/authorization/method-security.html
即使添加@Configuration后我也面临同样的问题。