将 hasRole 与自定义 JWT 身份验证过滤器一起使用时出现 Spring Security 403 错误

问题描述 投票:0回答:1

我正在使用 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 错误。

任何帮助将不胜感激!

java spring spring-boot
1个回答
0
投票

确保数据库或任何数据源中的角色列也具有前缀“ROLE_”(确保它们也使用前缀存储)

© www.soinside.com 2019 - 2024. All rights reserved.