首页 > 解决方案 > Keycloak + Spring Cloud Gateway + 认证授权

问题描述

我正在尝试在 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

我的 application.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 网关本身中进行身份验证和基于角色的授权。

标签: javaspring-bootoauth-2.0keycloak

解决方案


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: '{cipher}xxxx'
            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();
    }


推荐阅读