You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Keycloak认证通过后访问Spring Boot接口返回403 Forbidden问题

Troubleshooting 403 Forbidden After Keycloak Login in Spring Boot

Let's work through this 403 issue step by step. You've got authentication working (you can log in via Keycloak) but authorization is failing, which means your Spring Boot app isn't correctly recognizing the role you assigned in Keycloak. Here are the most likely fixes:

1. Fix Role Mapping Between Keycloak and Spring Security

Spring Security doesn't automatically parse Keycloak's realm roles from the JWT token by default. You need to add a custom converter to extract the realm_access.roles claim from the token and map it to Spring Security authorities.

First, add this bean to your SecurityConfig class:

@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
    JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
    // Point to Keycloak's realm roles claim
    grantedAuthoritiesConverter.setAuthoritiesClaimName("realm_access");
    // Add ROLE_ prefix to match Spring Security's hasRole() behavior
    grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");

    JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
    converter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
    return converter;
}

Then update your filterChain to use this converter for both OAuth2 login and resource server validation (since after login, your app uses the access token to protect endpoints):

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeRequests(auth -> auth
            .antMatchers("/public/**").permitAll()
            .anyRequest().hasRole("test")
        )
        .csrf(csrf -> csrf.disable())
        .oauth2Login(oauth2 -> oauth2
            .userInfoEndpoint(userInfo -> userInfo
                .jwtAuthenticationConverter(jwtAuthenticationConverter())
            )
        )
        .oauth2ResourceServer(oauth2 -> oauth2
            .jwt(jwt -> jwt
                .jwtAuthenticationConverter(jwtAuthenticationConverter())
            )
        )
        .logout(logout -> logout
            .addLogoutHandler(keycloakLogoutHandler)
            .logoutSuccessUrl("/")
        );
    return http.build();
}

2. Verify Keycloak Client Configuration

Double-check these settings in your Keycloak Console for the test2 client:

  • Access Type: Make sure it's set to confidential (you're using a client-secret, so this is required).
  • Valid Redirect URIs: Ensure it includes your Spring Boot app's callback URL, e.g., http://localhost:8081/* (replace 8081 with your app's actual port).
  • Scopes: Go to the Scopes tab and confirm roles is in the Default Client Scopes list. If not, add it—this ensures Keycloak includes role information in the JWT token.

3. Confirm Role Assignment and Case Sensitivity

  • Make sure the role you assigned to your user in Keycloak is exactly test (case-sensitive) to match the hasRole("test") rule in your security config.
  • Check that the user is actually assigned to this role: Go to Users > [your user] > Role Mappings > select your realm under Client Roles and verify test is in the Assigned Roles list.

4. Validate the JWT Token

To confirm Keycloak is sending the role correctly:

  1. After logging in, open your browser's dev tools (F12) and go to the Network tab.
  2. Look for a request to your protected endpoint and copy the Authorization header's access token (the part after Bearer ).
  3. Paste this token into jwt.io (you don't need to verify the signature, just check the payload).
  4. Ensure the realm_access field exists and includes "test" in the roles array, like this:
    "realm_access": {
      "roles": [
        "test",
        "default-roles-test"
      ]
    }
    

If this field is missing, go back to Keycloak's client scope settings to fix it.

5. Check Issuer URI Consistency

  • If your Spring Boot app is running in a Docker container, http://keycloak:8080/auth/realms/test is correct (since Docker Compose uses service names for DNS).
  • If you're running the app locally (outside Docker), you can keep using http://keycloak:8080/... thanks to your hosts file entry, but make sure the iss claim in the JWT matches this URI exactly (Keycloak's issuer is set to the URL it's accessed from, so if you logged in via localhost:8080, the iss will be http://localhost:8080/auth/realms/test—in that case, update your application.properties to match).

内容的提问来源于stack exchange,提问作者randomguy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 18:02:26