Sping Boot 应用程序在docker中使用keycloak进行保护,并使用nginx - configuration

u0njafvf  于 2023-08-03  发布在  Nginx
关注(0)|答案(1)|浏览(105)

我试图保护我的Sping Boot 应用程序在Docker中运行,同时也在Docker中运行Keycloak,但不知道如何做到这一点。
TL;DR
配置:
Docker与nginx,keycloak和springapp在localhost上运行。Postman客户端在localhost上运行。
问题:在内部docker的'keycloak'主机上通告keycloak,没有外部客户端可以连接到keycloak,因为这是它的内部docker主机名。如果keycloak配置了'localhost',docker中的springapp无法连接到keycloak,因为它正在尝试连接到自己。
详细信息:
配置:

  1. docker中的nginx充当反向代理,将'/auth'转发给keycloak,将'/API/springapp'转发给springapp:
upstream keycloak {
        server keycloak:8080;
    }
    upstream springapp {
        server springapp:8080;
    }

    server {
        listen 8080;
        server_name localhost;

        location /auth {
            proxy_pass http://keycloak;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-Host $host:$server_port;
            proxy_set_header X-Forwarded-Server $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location /api/springapp/ {
            proxy_pass http://springapp/;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-Host $host:$server_port;
            proxy_set_header X-Forwarded-Server $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

字符串
1.在端口8080上的Docker中的Keycloak:

keycloak:
    container_name: keycloak
    environment:
      - DB_VENDOR=postgres
      - DB_ADDR=postgres
      - DB_PORT=5432
      - DB_DATABASE=keycloak
      - DB_SCHEMA=keycloak
      - DB_USER=keycloak
      - DB_PASSWORD=kc123
      - KC_HTTP_RELATIVE_PATH=auth
      - KC_HOSTNAME_STRICT=false
      - KC_PROXY=edge
      - PROXY_ADDRESS_FORWARDING=true
#      - KEYCLOAK_FRONTEND_URL=https://keycloak:8080/auth
    expose:
      - "8080"
    networks:
      - docker-network

  1. springapp在docker中的端口8080:
springapp:
    container_name: springapp
    expose:
      - "8080"
    build: ./springapp
    env_file:
      - ./springapp/docker.env
    networks:
      - docker-network


问题:
当我在localhost上测试它时,keycloak hostname被设置为localhost。领域配置:

{
issuer: http://localhost:8080/auth/realms/myrealm,
authorization_endpoint: http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/auth,
token_endpoint: http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token,
introspection_endpoint: http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token/introspect,
userinfo_endpoint: http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/userinfo,
end_session_endpoint: http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/logout,
frontchannel_logout_session_supported: true,
frontchannel_logout_supported: true,
jwks_uri: http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/certs,
check_session_iframe: http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/login-status-iframe.html,
...
}


但由于springapp是在docker中运行的,它需要通过'keycloak'主机名连接到keycloak。
所以,当我使用

spring.security.oauth2.resourceserver.jwt.issuer-uri=http://keycloak:8080/auth/realms/myrealm

spring.security.oauth2.client.provider.myrealm.authorization-uri=http://keycloak:8080/auth/realms/myrealm/protocol/openid-connect/auth
spring.security.oauth2.client.provider.myrealm.token-uri=http://keycloak:8080/auth/realms/myrealm/protocol/openid-connect/token


我有iss mismatch error The iss claim is not valid,这是可以理解的,因为在iss声明中需要localhost。
但是如果我使用localhost,springapp当然不能连接到keycloak,因为它试图连接到localhost i。即其自身。
springboot配置:

@AllArgsConstructor
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class WebSecurityConfig
{
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception
    {
        httpSecurity
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
                                .anyRequest().permitAll()
                )
                .oauth2ResourceServer(configurer -> configurer
                        .jwt(jwtConfigurer -> jwtConfigurer
                                .jwtAuthenticationConverter(jwt -> {
                                    Map<String, Collection<String>> realmRolesMap = jwt.getClaim("realm_access");
                                    Collection<String> realmRoles = realmRolesMap.get("roles");
                                    if (realmRoles == null)
                                    {
                                        realmRoles = new ArrayList<>();
                                    }
                                    Map<String, Collection<String>> clientRolesMap = jwt.getClaim("resource_access");
                                    Collection<String> clientRoles = (Collection) ((Map) clientRolesMap.entrySet().iterator().next().getValue()).get("roles");
                                    if (clientRoles == null)
                                    {
                                        clientRoles = new ArrayList<>();
                                    }
                                    List<GrantedAuthority> grantedAuthorities = new Vector<>();

                                    grantedAuthorities = Stream.concat(realmRoles.stream(), clientRoles.stream())
                                            .distinct()
                                            .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                                            .collect(Collectors.toList());
                                    return new JwtAuthenticationToken(jwt, grantedAuthorities);
                                })))
        ;
        return httpSecurity.build();
    }
}


我该怎么解决这个问题?

o2gm4chl

o2gm4chl1#

像往常一样,我在发布问题后立即找到了答案。去掉了“localhost”,将其替换为DNS主机名。Stackoverflow帮助!- 谢谢-谢谢

相关问题