Keycloak Spring 安全客户端凭据授予 [英] Keycloak spring security client credential grant
问题描述
我可以在一个 keycloak 客户端与另一个 keycloak 客户端通信的情况下使用 KeycloakRestTemplate
.但是,它仅在我登录到第一个 keycloak 客户端时才有效,即将客户端 ID、客户端密码、用户名、密码发送到 keycloak 服务器.如果我没有在第一个客户端上使用用户和密码进行身份验证,我会收到无法设置授权标头,因为没有经过身份验证的原则".但是我已经将 keycloak 配置为对第一个客户端使用服务帐户(客户端凭据授予),因此我不应该使用用户/密码,而应该只依赖客户端 ID/秘密.这是 OAuth 2 规范的错误/偏差吗?
I can use KeycloakRestTemplate
where one keycloak client is communicating with another keycloak client. However it only works if I have logged into the first keycloak client, i.e. it sends client ID, client secret, username, password, to keycloak server. If I haven't authenticated with a user and password on the first client I get "Cannot set authorization header because there is no authenticated principle". But I have configured keycloak to use a service account for the first client (Client Credential Grant) therefore I should not be using a user/password and should be relying on client id/secret only. Is this is a bug/deviation from OAuth 2 spec?
推荐答案
KeycloakRestTemplate
将客户端 ID、客户端密码、用户名和密码发送到 Keycloak 服务器.我只想发送客户端 ID 和密码.我创建了 OAuth2RestTemplate
的 KeycloakClientCredentialsRestTemplate
子类来执行此操作.它使用 Spring Boot 中的 OAuth2 支持来授予客户端凭据.它还从 application.properties
获取 Keycloak 属性.
KeycloakRestTemplate
sends client ID, client secret, username and password to the Keycloak server. I wanted to only send client ID and secret. I created a KeycloakClientCredentialsRestTemplate
subclass of OAuth2RestTemplate
to do this. It uses OAuth2 support in Spring Boot to do a client credentials grant. It also takes Keycloak properties from application.properties
.
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;
}
}
这篇关于Keycloak Spring 安全客户端凭据授予的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!