如何通过Keycloak认证模块实现REST API模块的SSO权限管控?
基于Spring Boot的Keycloak SSO保护REST API+Swagger集成方案
针对你提到的两个模块(Keycloak+Swagger集成模块、需SSO保护的REST API模块),以下是稳定可行的配置方案——放弃易出问题的旧Keycloak适配器,采用Spring官方OAuth2组件实现:
1. 先完成Keycloak服务端基础配置
确保Keycloak后台已完成以下配置:
- 创建专属Realm(比如
my-realm) - 为API模块创建客户端:访问类型选
confidential,开启Service Accounts Enabled,记录客户端ID和密钥 - 为Swagger模块创建客户端:访问类型选
public,重定向URI设为http://localhost:8081/swagger-ui/**(对应Swagger模块端口),记录客户端ID - 为测试用户分配对应角色(比如
api-access),确保角色在Realm的realm_access.roles字段中
2. 受保护的REST API模块配置
2.1 依赖配置(pom.xml)
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
2.2 配置文件(application.yml)
spring: security: oauth2: resourceserver: jwt: issuer-uri: http://localhost:8080/realms/my-realm jwk-set-uri: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs server: port: 8082 # API模块独立端口
2.3 Spring Security核心配置
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.oauth2.server.resource.authentication.JwtAuthenticationConverter; import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class ApiSecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .anyRequest().authenticated() // 所有API接口强制认证 ) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter())) ); return http.build(); } // 可选:将Keycloak角色映射为Spring Security权限 private JwtAuthenticationConverter jwtAuthenticationConverter() { JwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter(); converter.setAuthorityPrefix("ROLE_"); converter.setAuthoritiesClaimName("realm_access.roles"); JwtAuthenticationConverter authConverter = new JwtAuthenticationConverter(); authConverter.setJwtGrantedAuthoritiesConverter(converter); return authConverter; } }
配置完成后,所有API接口会强制要求请求头携带Authorization: Bearer <JWT_TOKEN>,未携带或无效Token会返回401。
3. Keycloak+Swagger集成模块配置
3.1 依赖配置(pom.xml)
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency> </dependencies>
3.2 配置文件(application.yml)
spring: security: oauth2: client: registration: keycloak: client-id: swagger-client # 对应Keycloak中创建的Swagger客户端ID scope: openid, profile, api-access authorization-grant-type: authorization_code redirect-uri: "{baseUrl}/login/oauth2/code/keycloak" provider: keycloak: issuer-uri: http://localhost:8080/realms/my-realm user-name-attribute: preferred_username server: port: 8081 # Swagger模块独立端口 springdoc: swagger-ui: oauth: client-id: swagger-client realm: my-realm app-name: API测试客户端 use-pkce-with-authorization-code-grant: true
3.3 Spring Security配置
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 SwaggerSecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() .anyRequest().authenticated() ) .oauth2Login(oauth2 -> oauth2 .defaultSuccessUrl("/swagger-ui/index.html", true) // 登录成功后跳转到Swagger UI ); return http.build(); } }
3.4 Swagger OpenAPI配置
import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class OpenApiConfig { @Bean public OpenAPI customOpenAPI() { return new OpenAPI() .addSecurityItem(new SecurityRequirement().addList("BearerAuth")) .components(new Components() .addSecuritySchemes("BearerAuth", new SecurityScheme() .type(SecurityScheme.Type.HTTP) .scheme("bearer") .bearerFormat("JWT") .in(SecurityScheme.In.HEADER) .name("Authorization") ) ); } }
配置完成后,访问Swagger UI会自动跳转到Keycloak登录页,登录成功后可通过Swagger的「Authorize」按钮携带Token调用受保护的API接口。
常见启动问题排查
- 若之前用旧Keycloak适配器启动失败,直接切换到上述Spring OAuth2方案即可——Keycloak官方已弃用旧适配器,Spring 3+完全兼容OAuth2组件
- 检查
issuer-uri是否可访问:确保Keycloak服务正常,能打开http://localhost:8080/realms/my-realm/.well-known/openid-configuration - 客户端配置校验:API模块客户端必须是
confidential类型,Swagger模块若为public类型则不能配置client-secret - 端口冲突:两个模块必须使用不同端口
内容的提问来源于stack exchange,提问作者FAIZ
相关产品推荐
相关产品推荐

