Мне не удается заставить Keycloak работать в docker Compose. У меня есть базовый c Spring Boot REST API, который использует новый стек OAuth от Spring Security для работы в качестве сервера ресурсов. Я настроил сервер аутентификации Keycloak для импорта области при первом запуске. Я пытаюсь использовать поток учетных данных клиента. Он отлично работает, когда API запускается локально, но когда я запускаю его в docker -compose, он терпит неудачу с 401 Unauthorized еще до того, как достигнет конечной точки. Из того, что я читал, это потенциально ошибка cors, поскольку предварительный запрос запускает 401, но ни одна из конфигураций, с которыми я играл, не сработала. Когда я пытаюсь получить доступ с помощью curl, ответ указывает, что это недопустимый токен. Я тоже рассмотрел некоторые распространенные проблемы, такие как смещение часового пояса и многое другое, но также, похоже, не является виновником. Я обновил свой файл etc/hosts
, поэтому я могу изменить утверждение iss
на keycloak:8081
, но это тоже не помогает. Для ясности, я могу войти в систему без проблем, и если я выключу .authorizeRequests().anyRequest().authenticated().and().oauth2ResourceServer().jwt()
, он также будет работать.
version: "3.8"
services:
mariadb:
image: mariadb:10.5.3
environment:
MYSQL_ROOT_PASSWORD: root_password
MYSQL_DATABASE: keycloak
MYSQL_USER: some_user
MYSQL_PASSWORD: password
container_name: mariadb-10.5.3
networks:
- app
volumes:
- "auth:/var/lib/mysql"
auth:
build:
context: ./auth/
args:
- JAVA_VERSION=14
image: auth:1.0.0.1
container_name: auth-1.0.0.1
ports:
- "8081:8081"
environment:
KEYCLOAK_DB_PROTOCOL: mysql
KEYCLOAK_DB_HOST: mariadb
KEYCLOAK_DB_PORT: 3306
KEYCLOAK_DB_NAME: keycloak
KEYCLOAK_DB_USERNAME: some_user
KEYCLOAK_DB_PASSWORD: password
KEYCLOAK_DB_DRIVER: org.mariadb.jdbc.Driver
KEYCLOAK_CONTEXT_PATH: /auth
depends_on:
- mariadb
entrypoint:
["./wait-for-it.sh", "mariadb:3306", "--", "java", "-jar", "/app.jar"]
networks:
- app
api:
build:
context: ./api/
args:
- JAVA_VERSION=14
image: api:1.0.0.1
container_name: api-1.0.0.1
ports:
- "8080:8080"
environment:
KEYCLOAK_HOST: keycloak
KEYCLOAK_PORT: 8081
KEYCLOAK_CONTEXT_PATH: /auth
KEYCLOAK_REALM: api
ELASTICSEARCH_HOST: elasticsearch
ELASTICSEARCH_PORT: 9200
depends_on:
- elasticsearch
- auth
entrypoint:
[
"./wait-for-it.sh",
"elasticsearch:9200",
"--",
"java",
"-jar",
"/app.jar",
]
networks:
- app
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.7.1
container_name: elasticsearch-7.7.1
environment:
discovery.type: single-node
ports:
- "9200:9200"
- "9300:9300"
networks:
- app
- elk
kibana:
image: docker.elastic.co/kibana/kibana-oss:7.7.1
container_name: kibana-7.7.1
depends_on:
- elasticsearch
ports:
- "5601:5601"
networks:
- elk
logstash:
build:
context: ./elk/logstash/
image: logstash:7.7.1
container_name: logstash-7.7.1
depends_on:
- elasticsearch
environment:
PIPELINE_WORKERS: 1
networks:
- elk
networks:
elk:
name: elk
app:
name: app
volumes:
auth:
name: auth
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) // enables PreAuthorize annotation
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
}
api - application.properties
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://\${KEYCLOAK_HOST:localhost}:\${KEYCLOAK_PORT}/\${KEYCLOAK_CONTEXT_PATH:auth}/realms/\${KEYCLOAK_REALM}
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://\${KEYCLOAK_HOST:localhost}:\${KEYCLOAK_PORT}/\${KEYCLOAK_CONTEXT_PATH:auth}/realms/\${KEYCLOAK_REALM}/protocol/openid-connect/certs
keycloak - application.yaml
keycloak:
cors: true
server:
contextPath: ${KEYCLOAK_CONTEXT_PATH:/auth}
adminUser:
username: admin
password: admin
realmImportFile:
- api-realm.json
controller
@RestController
@RequestMapping("/")
public class Controller {
@Autowired
IDocumentRepository documentRepository;
@GetMapping("/{id}")
@PreAuthorize("@authorizationService.checkClientIDMatchesID(#token, #id)")
public Iterable<Documents> getAll(@AuthenticationPrincipal Jwt token, @PathVariable("id") String id) {
return documentRepository.findById(id);
}
}
пользовательский метод авторизации
@Service
public class AuthorizationService {
private static final Logger logger = LoggerFactory.getLogger(AuthorizationService.class);
public boolean checkClientIDMatchesID(Jwt token, String id)
{
if (id == null || token == null || token.getClaimAsBoolean("clientId") == null) return false;
return ((String)token.getClaim("clientId")).equalsIgnoreCase(id);
}
}
Вот логи для API:
And for Keycloak:
curl response:
введите описание изображения здесь
Я поигрался с его декодированием на jwt.io, и он говорит, что подпись не проверена, ключ publi c не делает ее действительной.