Keycloak + Spring Cloud Gateway + 认证授权

Posted

技术标签:

【中文标题】Keycloak + Spring Cloud Gateway + 认证授权【英文标题】:Keycloak + spring cloud gateway + authentication and authorization 【发布时间】:2021-11-20 17:43:37 【问题描述】:

我正在尝试在 spring 云网关本身中使用 keycloak 进行身份验证和授权。但我收到以下错误。

Caused by: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'springSecurityFilterChain' defined in class path resource [poc/apigateway/SecurityConfig.class]: 
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: 
Failed to instantiate [org.springframework.security.web.server.SecurityWebFilterChain]: 
Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.IllegalArgumentException: 
clientRegistrationRepository cannot be null

我的应用程序.properties

spring.application.name=api-gateway

spring.cloud.gateway.default-filters=TokenRelay

spring.cloud.gateway.routes[0].id=product-service
spring.cloud.gateway.routes[0].uri=http://localhost:8009
spring.cloud.gateway.routes[0].predicates[0]=Path=/api/product

spring.cloud.gateway.routes[1].id=order-service
spring.cloud.gateway.routes[1].uri=http://localhost:8008
spring.cloud.gateway.routes[1].predicates[0]=Path=/api/order

spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8080/auth/realms/microservice-realm
spring.security.oauth2.client.registration.spring-cloud-gateway-client.client-id=spring-cloud-gateway-client
spring.security.oauth2.client.registration.spring-cloud-gateway-client.client-secret=d1b3670c-f1c3-480c-9cda-8e107aec7d5b
spring.security.oauth2.client.registration.spring-cloud-gateway-client.scope=openid, profile, roles
spring.security.oauth2.client.registration.spring-cloud-gateway-client.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.spring-cloud-gateway-client.redirect-uri=http://localhost:8005/login/oauth2/code/spring-cloud-gateway-client

spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/auth/realms/microservice-realm

keycloak.realm=microservice-realm
keycloak.resource=spring-cloud-gateway-client
keycloak.auth-server-url=http://localhost:8080/auth
keycloak.public-client=true

keycloak.securityConstraints[0].authRoles[0]=app-user
keycloak.securityConstraints[0].securityCollections[0].patterns[0]=/api/*

我的 build.gradle

plugins 
    id 'org.springframework.boot' version '2.5.4'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'


group = 'poc'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories 
    mavenCentral()


ext 
    set('springCloudVersion', "2020.0.3")
    set('keycloakVersion', '4.8.3.Final')


dependencies 

    implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'

    // Keycloak
    implementation 'org.keycloak:keycloak-spring-boot-starter'


dependencyManagement 
    imports 
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:$springCloudVersion"
        mavenBom "org.keycloak.bom:keycloak-adapter-bom:$keycloakVersion"
    


test 
    useJUnitPlatform()

我的 SecurityConfig.java

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig 

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) 
        http.authorizeExchange(exchanges -> exchanges.anyExchange().authenticated())
                .oauth2Login(withDefaults());
        http.csrf().disable();
        return http.build();
    

问题出现在应用程序启动时。我在这里要做的是在 API 网关本身中进行身份验证和基于角色的授权。

【问题讨论】:

【参考方案1】:

Keycloak 适配器不适用于 WebFlux,只能用于 MVC,因此您应该删除此依赖项:

mavenBom "org.keycloak.bom:keycloak-adapter-bom:$keycloakVersion"

你可以使用

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>

并将 Keycloak 配置为 Oauth 服务器:

spring:
  security:
    oauth2:
      client:
        registration:
          keycloak:
            provider: keycloak
            client-id: web
            client-secret: 'cipherxxxx'
            authorization-grant-type: authorization_code
            redirect-uri: $keycloak-client.server-url/login/oauth2/code/keycloak
            scope: openid
        provider:
          keycloak:
            authorization-uri: $keycloak-client.server-url/realms/$keycloak-client.realm/protocol/openid-connect/auth
            token-uri: $keycloak-client.server-url/realms/$keycloak-client.realm/protocol/openid-connect/token
            user-info-uri: $keycloak-client.server-url/realms/$keycloak-client.realm/protocol/openid-connect/userinfo
            jwk-set-uri: $keycloak-client.server-url/realms/$keycloak-client.realm/protocol/openid-connect/certs
            user-name-attribute: name
            user-info-authentication-method: header
      resourceserver:
        jwt:
          jwk-set-uri: $keycloak-client.server-url/realms/$keycloak-client.realm/protocol/openid-connect/certs
keycloak-client:
  server-url: https://keycloakURL/auth
  realm: your-realm

还有过滤链:

  @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) 
        http
                .authorizeExchange()
                .pathMatchers(constraintsConfig.getOpenUri())
                .permitAll()
                .and()
                .authorizeExchange()
                .anyExchange().authenticated()
                .and()
                .oauth2ResourceServer()
                .jwt();
        return http.build();
    

【讨论】:

以上是关于Keycloak + Spring Cloud Gateway + 认证授权的主要内容,如果未能解决你的问题,请参考以下文章

带有 keycloak 的 Spring Cloud 微服务

spring api gateway 不会将我重定向到 keycloak 提供的 spring-cloud-gateway-client url

尽管设置了承载令牌,但 Spring Cloud Gateway 重定向到 Keycloak 登录页面

如何使用 Keycloak 保护 Angular 8 前端和使用网关、eureka 的 Java Spring Cloud 微服务后端

仅使用承载保护 Spring Cloud Gateway

spring-cloud-starter-consul-config 和 spring-cloud-consul-config 区别是什么?从网上没有搜到答案,待跟进。