我试图保护我的Sping Boot 应用程序在Docker中运行,同时也在Docker中运行Keycloak,但不知道如何做到这一点。
TL;DR
配置:
Docker与nginx,keycloak和springapp在localhost上运行。Postman客户端在localhost上运行。
问题:在内部docker的'keycloak'主机上通告keycloak,没有外部客户端可以连接到keycloak,因为这是它的内部docker主机名。如果keycloak配置了'localhost',docker中的springapp无法连接到keycloak,因为它正在尝试连接到自己。
详细信息:
配置:
- 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
型
- 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();
}
}
型
我该怎么解决这个问题?
1条答案
按热度按时间o2gm4chl1#
像往常一样,我在发布问题后立即找到了答案。去掉了“localhost”,将其替换为DNS主机名。Stackoverflow帮助!- 谢谢-谢谢