我正在使用 Spring Security 和自定义 JWT 身份验证过滤器,但我面临一个问题,即在尝试访问需要特定角色的端点时收到 403 Forbidden 错误。 PermitAll() 配置工作正常,但使用 hasRole() 或 hasAnyAuthority() 似乎不起作用。
这是我的 Spring Security 配置:
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth ->
auth.requestMatchers("/v1/api/public/**").permitAll()
.requestMatchers("/v1/api/authorized/**").hasRole("USER")
.anyRequest().authenticated())
.sessionManagement(sessionManagement ->
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); // Add custom filter
return http.build();
}
这是我的自定义 JWT 过滤器:
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserService userService;
public JwtAuthenticationFilter(JwtService jwtService, UserService userService) {
this.jwtService = jwtService;
this.userService = userService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
final String header = request.getHeader("Authorization");
if (header != null && header.startsWith("Bearer ")) {
final String jwt = header.substring(7);
String username = jwtService.extractUsername(jwt);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
User user = userService.getUserByUsername(username);
if (jwtService.validateToken(jwt, user)) {
CustomUserDetails userDetails = new CustomUserDetails(user);
// Create an authentication token
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
// Set the authentication token in the SecurityContext
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
}
// Continue the filter chain
filterChain.doFilter(request, response);
}
}
还有我的 CustomUserDetails 类:
public class CustomUserDetails implements UserDetails {
private final User user;
public CustomUserDetails(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority("ROLE_USER"), new SimpleGrantedAuthority("ROLE_ADMIN"));
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getEmail();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
public User getUser() {
return user;
}
}
问题: 当我尝试访问需要角色的端点(@PreAuthorize("hasRole('USER')") 或 hasRole("USER")) 时,我仍然收到 403 Forbidden 错误。 但是,permitAll() 工作正常,这意味着过滤器已正确执行并且 JWT 正在验证。 我尝试过的: 我尝试过同时使用 hasRole("USER") 和 hasAnyAuthority("ROLE_USER", "ROLE_ADMIN") 但都不起作用。 我检查了 GrantedAuthority 和 SecurityContextHolder 中的角色,它们被正确设置为 ROLE_USER 和 ROLE_ADMIN。 我也在控制器方法上使用 @PreAuthorize 注释。 预期行为: 我希望具有 ROLE_USER 或 ROLE_ADMIN 的用户被授予访问 /v1/api/authorized/** 端点的权限,而不会收到 403 错误。
任何帮助将不胜感激!
确保数据库或任何数据源中的角色列也具有前缀“ROLE_”(确保它们也使用前缀存储)