You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Keycloak OAuth2出现[authorization_request_not_found]错误求助

微服务集成Keycloak实现OAuth2认证时出现[authorization_request_not_found]错误

在微服务架构(包含auth-service和gateway)中,通过docker-compose部署所有服务及Keycloak,集成Keycloak实现OAuth2认证时,页面抛出[authorization_request_not_found]错误。


一、环境配置

1. Docker-Compose配置

gateway-server:
    image: 'gateway-server:1.0'
    container_name: gateway
    ports:
      - "8080:8080"
    restart: on-failure
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka
    depends_on:
      - eureka-server
    networks:
      - mynet

  auth-server:
    image: 'auth-service:1.0'
    container_name: auth-server
    ports:
      - "8081:8081"
    restart: on-failure
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka
      - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/mydb
      - SPRING_DATASOURCE_USERNAME=username
      - SPRING_DATASOURCE_PASSWORD=password
    depends_on:
      - eureka-server
      - db
      - keycloak-service
    networks:
      - mynet

keycloak-service:
    image: 'keycloak/keycloak:latest'
    container_name: keycloak-service
    environment:
      - KEYCLOAK_ADMIN=admin
      - KEYCLOAK_ADMIN_PASSWORD=password
    ports:
      - "8085:8085"
    command:
      - start-dev
      - --http-port=8085
    restart: always
    networks:
      mynet:
        aliases:
          - keycloak-service:8085


networks:
  mynet:

2. Hosts文件配置

127.0.0.1   localhost
127.0.0.1   keycloak-service

3. Keycloak配置类

@Configuration
@Getter
@Setter
@RequiredArgsConstructor
@ConfigurationProperties("keycloak")
public class KeycloakConfig {

    private String serverUrl;

    private String realm;

    private String clientId;

    private String username;

    private String password;

    private String roleBuyer;

    private String roleAdmin;

    private String secret;

    @Bean
    public Keycloak keycloak() {
        ResteasyClientBuilder resteasyClientBuilder = new ResteasyClientBuilderImpl();

        Keycloak keycloak = KeycloakBuilder.builder()
                .serverUrl(serverUrl)
                .grantType(OAuth2Constants.PASSWORD)
                .realm("master")
                .clientId("admin-cli")
                .username(username)
                .password(password)
                .resteasyClient(resteasyClientBuilder.connectionPoolSize(10).build())
                .build();

        RealmRepresentation newRealm = new RealmRepresentation();
        newRealm.setId(realm);
        newRealm.setRealm(realm);
        newRealm.setEnabled(true);

        keycloak.realms().create(newRealm);

        ClientRepresentation clientRepresentation = new ClientRepresentation();
        clientRepresentation.setClientId(clientId);
        clientRepresentation.setRedirectUris(List.of("http://127.0.0.1:8080/auth-service/*"));
        clientRepresentation.setWebOrigins(List.of("http://127.0.0.1:8080/auth-service"));
        clientRepresentation.setSecret(secret);

        keycloak.realm(realm).clients().create(clientRepresentation);

        RoleRepresentation role1 = new RoleRepresentation();
        role1.setId(roleBuyer);
        role1.setName(roleBuyer);
        role1.setClientRole(true);

        RoleRepresentation role2 = new RoleRepresentation();
        role2.setId(roleAdmin);
        role2.setName(roleAdmin);
        role2.setClientRole(true);

        keycloak.realm(realm).roles().create(role1);
        keycloak.realm(realm).roles().create(role2);

        return keycloak;
    }
}

4. 安全配置类

@Configuration
@EnableWebSecurity
@Getter@Setter
public class MyConfig {

    @Value("${keycloak.secret}")
    private String secret;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable();
        httpSecurity.authorizeHttpRequests()
                .anyRequest().authenticated()
                .and()
                .oauth2Login();
        httpSecurity.oauth2Client();

        return  httpSecurity.build();
    }

    @Bean
    public ClientRegistrationRepository clientRepository() {
        ClientRegistration keycloak = keycloakClientRegistration();
        return new InMemoryClientRegistrationRepository(keycloak);
    }

    private ClientRegistration keycloakClientRegistration() {

        return ClientRegistration.withRegistrationId("teamgeist")
                .clientId("teamgeist-backend")
                .clientSecret(secret)
                .scope("openid")
                .redirectUri("http://127.0.0.1:8080/auth-service/login/oauth2/code/teamgeist-backend")
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .issuerUri("http://keycloak-service:8085/realms/teamgeist")
                .authorizationUri("http://keycloak-service:8085/realms/teamgeist/protocol/openid-connect/auth")
                .tokenUri("http://keycloak-service:8085/realms/teamgeist/protocol/openid-connect/token")
                .userInfoUri("http://keycloak-service:8085/realms/teamgeist/protocol/openid-connect/userinfo")
                .build();
    }
}

5. application.properties配置

spring.security.oauth2.client.registration.keycloak.client-id=teamgeist-backend
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.keycloak.scope=openid
spring.security.oauth2.client.provider.keycloak.issuer-uri=http://keycloak-service:8085/realms/teamgeist
spring.security.oauth2.client.registration.keycloak.client-secret=${keycloak.secret}
spring.security.oauth2.client.registration.keycloak.redirect-uri=http://127.0.0.1:8080/auth-service/login/oauth2/code/teamgeist-backend

排查与解决方案

1. 统一重定向URI配置

authorization_request_not_found核心原因是授权请求会话不匹配,重点检查重定向URI一致性:

  • 修改KeycloakConfig中的客户端重定向URI,确保覆盖Spring的回调路径:
    clientRepresentation.setRedirectUris(List.of("http://127.0.0.1:8080/auth-service/login/oauth2/code/*"));
    
  • 保持Spring配置和Keycloak客户端配置的URI完全一致,避免localhost和127.0.0.1混用,统一使用同一格式。

2. 修正Keycloak外部访问地址

容器内部域名keycloak-service无法被浏览器解析,需将所有Keycloak相关配置替换为外部可访问地址:

  • 安全配置类中,将issuerUri、authorizationUri、tokenUri、userInfoUri中的keycloak-service替换为127.0.0.1
  • application.properties中的issuer-uri修改为http://127.0.0.1:8085/realms/teamgeist
  • KeycloakConfig中的serverUrl设置为http://127.0.0.1:8085

3. 解决会话丢失问题

由于网关转发,auth-service的授权会话可能丢失:

  • 配置全局会话存储(如Redis),确保auth-service的会话在网关转发后仍可访问。

4. 检查Keycloak客户端类型

确认Keycloak客户端的Access Type设置为confidential,authorization_code授权类型需要客户端密钥,必须开启此配置。

5. 避免重复创建Realm/客户端

当前KeycloakConfig每次启动都会重复创建Realm和客户端,可能导致配置冲突,添加判断逻辑:

// 仅在Realm不存在时创建
if (keycloak.realm(realm).find() == null) {
    keycloak.realms().create(newRealm);
}

// 仅在客户端不存在时创建
if (keycloak.realm(realm).clients().findByClientId(clientId).isEmpty()) {
    keycloak.realm(realm).clients().create(clientRepresentation);
}

内容的提问来源于stack exchange,提问作者Sonnka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 16:44:54