2017-09-06 232 views
0

我可以使用KecloakRestTemplate,其中一個keycloak客戶端正在與另一個keycloak客戶端進行通信。然而,只有當我登錄到第一個keycloak客戶端時它纔有效,即它將客戶端ID,客戶端密碼,用戶名,密碼發送到keycloak服務器。如果我沒有在第一個客戶端上使用用戶和密碼進行身份驗證,則會收到「無法設置授權標頭,因爲沒有經過身份驗證的原則」。但是我已經配置了keycloak爲第一個客戶端使用服務帳戶(Client Credential Grant),因此我不應該使用用戶/密碼,並且應該僅依賴於客戶端ID /密碼。這是否是OAuth 2規範的錯誤/偏差?Keycloak彈簧安全客戶端憑證授權

回答

0

對於基於微服務架構的應用程序,我使用用戶和客戶端帳戶。我猜Spring安全適配器只處理用戶相關的東西(我使用的版本,至少是2.2.1)。我所做的是另一個RestTemplate,我爲了作爲客戶訪問資源而自行處理。

舉個例子:

@Service 
public class RemoteAccessService{ 

    //Manages user access 
    private KeycloakRestTemplate userAccessRestTemplate; 

    //Manages client access 
    private RestTemplate clientAccessRestTemplate; 

    public RemoteAccessService(KeycloakRestTemplate userAccessRestTemplate, 
     @Qualifier("clientAccessRestTemplate") RestTemplate clientAccessRestTemplate;){ 

    } 

} 

然後,建立一個@ConfigurationRestTemplate豆,以管理客戶端授權:

@Bean 
public RestTemplate clientAccessRestTemplate() { 
    RestTemplate template = new RestTemplate(); 
    template.getMessageConverters().add(new FormHttpMessageConverter()); 
    template.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); 
    template.getInterceptors().add(new ClientHttpRequestInterceptor() { 

     @Override 
     public ClientHttpResponse intercept(HttpRequest request, byte[] body, 
       ClientHttpRequestExecution execution) throws IOException { 
      //Intercept each of the requests performed by this template 
      //and add the client access token in the Authorization header 
      HttpRequest wrapper = new HttpRequestWrapper(request); 
      if (clientAccessToken != null) { 
       wrapper.getHeaders().set("Authorization", 
         "Bearer " + clientAccessToken.getToken()); 
      } 
      return execution.execute(wrapper, body); 
     } 
    }); 
    return template; 
} 

當然,你需要確保你」已經在攔截器中獲得了正確的clientAccessToken,否則你將得到401或403代碼。在這裏,您已經獲得了關於如何在OAuth中執行此操作的post(您不需要用戶/密碼,只需要客戶端憑據)。

作爲旁註,keycloak適配器可以方便地管理某些情況,但它們不提供對keycloak所有功能的訪問,這是一種更強大的方式。

0

KeycloakRestTemplate將客戶端ID,客戶端密碼,用戶名和密碼發送到Keycloak服務器。我只想發送客戶端ID和密碼。我創建了一個KeycloakClientCredentialsRestTemplate子類OAuth2RestTemplate來做到這一點。它在Spring Boot中使用OAuth2支持來執行客戶端憑據授權。它還需要application.properties的Keycloak屬性。

import org.springframework.security.oauth2.client.OAuth2ClientContext; 
import org.springframework.security.oauth2.client.OAuth2RestTemplate; 
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; 

public class KeycloakClientCredentialsRestTemplate extends OAuth2RestTemplate { 

    public KeycloakClientCredentialsRestTemplate(OAuth2ProtectedResourceDetails resource, 
      OAuth2ClientContext context) { 
     super(resource, context); 
    } 

} 

另外:

import java.util.ArrayList; 
import java.util.List; 

import org.springframework.beans.factory.annotation.Value; 
import org.springframework.context.annotation.Bean; 
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext; 
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails; 
import org.springframework.security.oauth2.common.AuthenticationScheme; 
import org.springframework.stereotype.Service; 

@Service 
public class KeycloakClientCredentialsConfig { 

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

    @Value("${keycloak.auth-server-url}") 
    private String authServerUrl; 

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

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

    @Bean 
    public KeycloakClientCredentialsRestTemplate createRestTemplate() { 
     return new KeycloakClientCredentialsRestTemplate(getClientCredentialsResourceDetails(), 
       new DefaultOAuth2ClientContext()); 
    } 

    private ClientCredentialsResourceDetails getClientCredentialsResourceDetails() { 
     String accessTokenUri = String.format("%s/realms/%s/protocol/openid-connect/token", 
      authServerUrl, realm); 
     List<String> scopes = new ArrayList<String>(0); // TODO introduce scopes 

     ClientCredentialsResourceDetails clientCredentialsResourceDetails = 
       new ClientCredentialsResourceDetails(); 

     clientCredentialsResourceDetails.setAccessTokenUri(accessTokenUri); 
     clientCredentialsResourceDetails.setAuthenticationScheme(AuthenticationScheme.header); 
     clientCredentialsResourceDetails.setClientId(clientId); 
     clientCredentialsResourceDetails.setClientSecret(clientSecret); 
     clientCredentialsResourceDetails.setScope(scopes); 

     return clientCredentialsResourceDetails; 
    } 

}