Spring Boot集成Keycloak:如何通过有效JWT令牌直接访问API
Hey there! Let's get your Spring Boot app set up to accept valid Keycloak JWT tokens directly—no more redirecting when the user already has a valid token. Here's exactly what you need to do:
First, make sure your pom.xml includes these dependencies to enable Spring Security's OAuth2 resource server support:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency>
Update your application.yml (or application.properties) to tell Spring Boot how to validate Keycloak-issued JWTs:
spring: security: oauth2: resourceserver: jwt: # Replace with your Keycloak realm URL issuer-uri: http://localhost:8081/auth/realms/your-realm-name # Auto-fetch public keys from Keycloak to verify JWT signatures jwk-set-uri: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs
This is the core step—we'll configure Spring Security to support both authentication flows:
- Redirect to Keycloak login when no token is present (keeping your existing working flow)
- Validate JWT directly when a valid token is provided in the request
Create a security configuration class:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // Require authentication for all requests .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) // Keep your existing redirect-to-Keycloak login flow .oauth2Login(oauth2 -> oauth2.loginPage("/oauth2/authorization/keycloak")) // Add support for JWT token validation .oauth2ResourceServer(oauth2 -> oauth2.jwt()); return http.build(); } }
Optional: Customize JWT Role Extraction
If your app uses roles from Keycloak, you can add a custom converter to extract realm roles from the JWT:
import org.springframework.core.convert.converter.Converter; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter; import java.util.Collection; import java.util.stream.Collectors; import java.util.stream.Stream; public class KeycloakJwtAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken> { private final JwtGrantedAuthoritiesConverter defaultConverter = new JwtGrantedAuthoritiesConverter(); @Override public AbstractAuthenticationToken convert(Jwt jwt) { // Combine default authorities with Keycloak realm roles Collection<GrantedAuthority> authorities = Stream.concat( defaultConverter.convert(jwt).stream(), ((Collection<String>) jwt.getClaimAsMap("realm_access").get("roles")) .stream() .map(role -> new SimpleGrantedAuthority("ROLE_" + role)) ).collect(Collectors.toSet()); return new JwtAuthenticationToken(jwt, authorities); } }
Then update the security config to use this converter:
// Modify the oauth2ResourceServer section in SecurityConfig .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt .jwtAuthenticationConverter(new KeycloakJwtAuthenticationConverter()) ) );
If you need to access token details in your endpoint, inject JwtAuthenticationToken into your method:
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class Table1Controller { @Autowired private ITable1Repository table1Repository; @GetMapping("/table1data") public List<Table1Entity> getAllTable1Data(JwtAuthenticationToken authentication) { // Example: Get current username from token String currentUser = authentication.getName(); // Example: Get custom claim from token String userEmail = authentication.getToken().getClaim("email"); return table1Repository.findAll(); } }
- With Valid JWT: In Postman, send a GET request to
http://localhost:8080/table1datawith the headerAuthorization: Bearer <your-keycloak-jwt-token>. You'll get the data directly without redirect. - Without JWT: Visit the URL directly, and you'll be redirected to the Keycloak login page as before.
Important Notes
- Ensure your Keycloak client is configured correctly: If you're using password flow to generate tokens, enable "Direct Access Grants Enabled" in the client settings.
- The JWT's
aud(audience) claim must match your Keycloak client ID for validation to pass.
内容的提问来源于stack exchange,提问作者Mirza Bilal




