Spring Security Role-Based Authorization Issue: 403 Forbidden Error

86 views Asked by At

Problem:

I am trying to create a Spring-based web server with role-based authentication, but I consistently receive a 403 Forbidden error. I have implemented a custom UserDetails class, and I suspect there might be an issue with my configuration.

Code:

Custom UserDetails:

public class CustomUserDetails implements UserDetails {
    private static final long serialVersionUID = 1L;
    private final User user;

    public CustomUserDetails(User user) {
        this.user = user;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return user.getRoles().stream().map(r -> new SimpleGrantedAuthority("ROLE_" + r.getName())).toList();
    }

    // ... other UserDetails methods
}

SecurityFilterChain implementation:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        .csrf(csrf -> csrf.disable())
        .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .authorizeHttpRequests(requests -> requests
            .requestMatchers("/api/**").permitAll()
            .requestMatchers("/secret/**").hasAuthority("USER")
            .anyRequest().authenticated())
        .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
        .addFilterBefore(authorizeFilter, UsernamePasswordAuthenticationFilter.class)
        .build();
}

I've implemented a custom UserDetails class and configured Spring Security for role-based authentication. However, I keep encountering a 403 Forbidden error, even though I believe the roles are correctly assigned. I've tried using both hasRole and hasAuthority, but the issue persists. What am I missing in my configuration?

Any insights or suggestions would be greatly appreciated. Thank you!

2

There are 2 answers

3
ch4mp On BEST ANSWER

For resource servers with JWTs, authorities are set by the authentication converter.

The default authentication converter is JwtAuthenticarionConverter, which delegates authorities convertion to a configurable authorities converter (the default uses the entries in scope claim adding SCOPE_ prefix).

You can provide a JwtAuthenticationConverter configured with another authorities converter (one using another claim as source for authorities), or switch to a completely different Converter<Jwt,? extends AbstractAuthenticationToken> by using http.oauth2ResourceServer(oauth2-> oauth2.jwt(Jwt -> jwt.jwtAuthenticationConverter(...))

You might also consider this additional starter I maintain which uses an authorities converter configurable with just application properties (unless you provide your own authorities or authentication converter in your conf)

0
xiaotiaz On

You can try to open the TRACE log for spring and find out where the question happers. This suggestion may not help you directly, but it did help us find the reason why the API returned 403 when we migrated to Springboot3.0