Я пытаюсь реализовать аутентификацию во всех моих внутренних службах приложения, ориентированного на микросервисы, с использованием Keycloak и Spring Boot с Spring Security и JWT-токенами (настройка только для носителя в Keycloak).
У меня есть внутренний серверслужба, которая требует аутентификации для доступа к конечным точкам REST.Этот сервис предоставляет данные для веб-интерфейса, а также принимает данные для хранения в базе данных, чтобы их можно было обработать позже.Аутентификация пользователя в пользовательском интерфейсе, а также в пользовательском интерфейсе для этой серверной службы уже работает.
Затем существует другая вспомогательная служба, которая работает в фоновом режиме, вычисляя значения, которые также должны присутствовать в первой упомянутой серверной части.оказание услуг.Поскольку для этого требуется проверка подлинности, службе, выполняющей вычисления, сначала необходимо получить токен доступа из Keycloak для проверки подлинности по отношению к другой серверной службе для работы сообщения HTTP.
Я пытаюсь выполнить сообщение HTTP сKeycloakRestTemplate, но когда я вызываю метод .postForObject, я получаю исключение:
Caused by: java.lang.IllegalStateException: Cannot set authorization header because there is no authenticated principal
at org.keycloak.adapters.springsecurity.client.KeycloakClientRequestFactory.getKeycloakSecurityContext(KeycloakClientRequestFactory.java:70)
at org.keycloak.adapters.springsecurity.client.KeycloakClientRequestFactory.postProcessHttpRequest(KeycloakClientRequestFactory.java:55)
at org.springframework.http.client.HttpComponentsClientHttpRequestFactory.createRequest(HttpComponentsClientHttpRequestFactory.java:160)
Кажется, что служба вычислений не извлекает токен аутентификации автоматически перед вызовом другой службы REST.Я много раз изучал в Google все эти классы, связанные с Keycloak, но я не понял, что мне нужно делать.
Может кто-нибудь дать мне подсказку?Я также не знаю, какие части конфигурации Spring уместны здесь, но я предоставлю их, если они вам понадобятся.
РЕДАКТИРОВАТЬ
Мои application.properties изСлужба расчета выглядит следующим образом:
keycloak.auth-server-url=https://localhost/auth
keycloak.realm=myrealm
keycloak.bearer-only=true
keycloak.resource=backend-service2
keycloak.principal-attribute=preferred_username
keycloak.cors=true
keycloak.realm-key=<PUBKEY>
keycloak.credentials.secret=<SECRET_UUID_STYLE>
keycloak.use-resource-role-mappings=true
ОБНОВЛЕНИЕ
Спасибо @Sai prateek и @Xtreme Biker.Это, кажется, ведет меня в правильном направлении.
Я применил это решение, но я все еще получаю исключение, я думаю, что конфигурация keycloak неверна.У меня сейчас три клиента в keycloak: webui, backend-service1, backend-service2.
Webui настроен следующим образом: Тип доступа: public
Backend-service1 настроен как: Тип доступа: только для переноса
Бэкэнд-сервис2 настроен следующим образом: Тип доступа: только для переноса
Исключение составляет:
2019-02-18 11:15:32.914 DEBUG 22620 --- [ restartedMain] o.s.web.client.RestTemplate : POST request for "http://localhost:<PORT>/auth/realms/<REALM_NAME>/protocol/openid-connect/token" resulted in 400 (Bad Request); invoking error handler
Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: error="access_denied", error_description="Access token denied."
at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:142)
at org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider.obtainAccessToken(ClientCredentialsAccessTokenProvider.java:44)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:148)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:121)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.createRequest(OAuth2RestTemplate.java:105)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:683)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.doExecute(OAuth2RestTemplate.java:128)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:644)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:399)
[STRIPPED]
... 5 more
Caused by: error="invalid_client", error_description="Bearer-only not allowed"
at org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Deserializer.deserialize(OAuth2ExceptionJackson2Deserializer.java:80)
at org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Deserializer.deserialize(OAuth2ExceptionJackson2Deserializer.java:33)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3072)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:237)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readInternal(AbstractJackson2HttpMessageConverter.java:217)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:198)
at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport$AccessTokenErrorHandler.handleError(OAuth2AccessTokenSupport.java:237)
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:730)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:688)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:654)
at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:137)
... 18 more
Также обратите внимание, что я изменил *От 1038 * до http://localhost:<PORT>/auth
(без HTTPS), поэтому проверка сертификата не завершится неудачей из-за самозаверяющего сертификата в процессе разработки.