You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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:

Step 1: Add Required Dependencies

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>
Step 2: Configure Keycloak JWT Validation

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
Step 3: Update Security Configuration

This is the core step—we'll configure Spring Security to support both authentication flows:

  1. Redirect to Keycloak login when no token is present (keeping your existing working flow)
  2. 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())
    )
);
Step 4: Update Your Controller (Optional)

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();
    }
}
Step 5: Test the Flow
  • With Valid JWT: In Postman, send a GET request to http://localhost:8080/table1data with the header Authorization: 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

火山引擎 最新活动