带 Spring 的 Keycloak Boot KeycloakSecurityContext 始终为 null
Keycloak with Spring Boot KeycloakSecurityContext always null
我尝试将 Keycloak 与 spring 引导一起使用,但我遇到了问题。身份验证适用于适配器,但不适用于授权。
这是我的配置:
keycloak.realm = master
keycloak.auth-server-url = http://127.0.0.1:8080/auth
keycloak.ssl-required = none
keycloak.resource = pactng
keycloak.credentials.secret = **************************
keycloak.use-resource-role-mappings = true
keycloak.principal-attribute=preferred_username
keycloak.bearer-only = true
keycloak.policy-enforcer-config.userManagedAccess=org.keycloak.representations.adapters.config.PolicyEnforcerConfig.UmaProtocolConfig
keycloak.policy-enforcer-config.lazyLoadPaths=true
keycloak.policy-enforcer-config.paths[0].path=/*
keycloak.policy-enforcer-config.paths[0].methods[0].method=GET
keycloak.policy-enforcer-config.paths[0].methods[0].scopes[0]=urn:pactng:scopes:read
keycloak.policy-enforcer-config.paths[0].methods[1].method=POST
keycloak.policy-enforcer-config.paths[0].methods[1].scopes[0]=urn:pactng:scopes:create
keycloak.policy-enforcer-config.paths[0].methods[2].method=PUT
keycloak.policy-enforcer-config.paths[0].methods[2].scopes[0]=urn:pactng:scopes:update
keycloak.policy-enforcer-config.paths[0].methods[3].method=PATCH
keycloak.policy-enforcer-config.paths[0].methods[3].scopes[0]=urn:pactng:scopes:update
keycloak.policy-enforcer-config.paths[0].methods[4].method=DELETE
keycloak.policy-enforcer-config.paths[0].methods[4].scopes[0]=urn:pactng:scopes:delete
我没有在这里定义角色,我希望适配器根据访问令牌中包含的请求和权限动态计算授权。
这是我的 spring 安全 KeycloakConfig :
@KeycloakConfiguration
public class KeycloakConfig extends KeycloakWebSecurityConfigurerAdapter {
/**
* Map keycloak role to spring ROLE_<ROLE>
* @param auth
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
/**
* Defined the strategy use by keycloak for user session. We need authorization system so we use a session for a confidential client.
* Can be NullAuthenticatedSessionStrategy for bearerClient
* @return
*/
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
/**
* Use spring boot application.properties instead of keycloak.json to retrieve
* connexion informations
*/
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/*").authenticated()
.anyRequest().permitAll();
}
}
我通过使用以下请求检索令牌进行测试。 UMA 2 已激活,因为如果没有此适配器,似乎不可能启用授权。
# Get Access Token for a user.
POST http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/token
{
client_id "<CLIENT_ID>"
client_secret "<CLIENT_SECRET>"
username "<USERNAME>"
password "<USER_PASSWORD>"
grant_type "password"
}
这为我提供了一个访问令牌,我将在以下请求中使用它。
# Try to get access to the resource endpoint
GET http://localhost:8081/api/v1/<resources>
Headers: authorization: Bearer <ACCESS_TOKEN>
这给了我一个符合 UMA2 规范的 401 WWW-Authenticate 和一张票。然后我联系 keycloak 以获得 RPT :
# Get RPT from Keycloak
POST http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/token
Headers: authorization: Bearer <ACCESS_TOKEN>
{
grant_type: "urn:ietf:params:oauth:grant-type:uma-ticket"
ticket: <TICKET>
}
Keycloak 给我一个 RPT,它是一个访问令牌,其中包含权限。然后我重试获取资源,但使用此 RPT
# Try to get access to the resource endpoint
GET http://localhost:8081/api/v1/<resources>
Headers: authorization: Bearer <RPT>
但是适配器没有访问资源,而是再次给我一个 401 WWW-Authenticate。
我深入研究了代码,发现 KeycloakSecurityContext 在 AbstractPolicyEnforcer 中始终为空:
public AuthorizationContext authorize(OIDCHttpFacade httpFacade) {
EnforcementMode enforcementMode = getEnforcerConfig().getEnforcementMode();
// Always return null
KeycloakSecurityContext securityContext = httpFacade.getSecurityContext();
这使得代码每次都被困在这部分代码中:
if (securityContext == null) {
if (!isDefaultAccessDeniedUri(request)) {
if (pathConfig != null) {
if (EnforcementMode.DISABLED.equals(pathConfig.getEnforcementMode())) {
return createEmptyAuthorizationContext(true);
} else {
challenge(pathConfig, getRequiredScopes(pathConfig, request), httpFacade);
}
} else {
handleAccessDenied(httpFacade);
}
}
return createEmptyAuthorizationContext(false);
}
所以我的问题是,经过这么长的解释,为什么没有填充这个 securityContext?我错过了什么吗?
好的,我找到了解决方案。看起来这个适配器想要一个角色的 securityContraints 来完成它的工作。所以我添加这个以使其工作:
keycloak.securityConstraints[0].authRoles[0]=*
keycloak.securityConstraints[0].securityCollections[0].patterns[0]=/*
这基本上告诉它处理所有路径上的所有角色。
P.S 继续使用 JAVA 11,因为它与最新的 JDK 版本不兼容。
我尝试将 Keycloak 与 spring 引导一起使用,但我遇到了问题。身份验证适用于适配器,但不适用于授权。
这是我的配置:
keycloak.realm = master
keycloak.auth-server-url = http://127.0.0.1:8080/auth
keycloak.ssl-required = none
keycloak.resource = pactng
keycloak.credentials.secret = **************************
keycloak.use-resource-role-mappings = true
keycloak.principal-attribute=preferred_username
keycloak.bearer-only = true
keycloak.policy-enforcer-config.userManagedAccess=org.keycloak.representations.adapters.config.PolicyEnforcerConfig.UmaProtocolConfig
keycloak.policy-enforcer-config.lazyLoadPaths=true
keycloak.policy-enforcer-config.paths[0].path=/*
keycloak.policy-enforcer-config.paths[0].methods[0].method=GET
keycloak.policy-enforcer-config.paths[0].methods[0].scopes[0]=urn:pactng:scopes:read
keycloak.policy-enforcer-config.paths[0].methods[1].method=POST
keycloak.policy-enforcer-config.paths[0].methods[1].scopes[0]=urn:pactng:scopes:create
keycloak.policy-enforcer-config.paths[0].methods[2].method=PUT
keycloak.policy-enforcer-config.paths[0].methods[2].scopes[0]=urn:pactng:scopes:update
keycloak.policy-enforcer-config.paths[0].methods[3].method=PATCH
keycloak.policy-enforcer-config.paths[0].methods[3].scopes[0]=urn:pactng:scopes:update
keycloak.policy-enforcer-config.paths[0].methods[4].method=DELETE
keycloak.policy-enforcer-config.paths[0].methods[4].scopes[0]=urn:pactng:scopes:delete
我没有在这里定义角色,我希望适配器根据访问令牌中包含的请求和权限动态计算授权。
这是我的 spring 安全 KeycloakConfig :
@KeycloakConfiguration
public class KeycloakConfig extends KeycloakWebSecurityConfigurerAdapter {
/**
* Map keycloak role to spring ROLE_<ROLE>
* @param auth
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
/**
* Defined the strategy use by keycloak for user session. We need authorization system so we use a session for a confidential client.
* Can be NullAuthenticatedSessionStrategy for bearerClient
* @return
*/
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
/**
* Use spring boot application.properties instead of keycloak.json to retrieve
* connexion informations
*/
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/*").authenticated()
.anyRequest().permitAll();
}
}
我通过使用以下请求检索令牌进行测试。 UMA 2 已激活,因为如果没有此适配器,似乎不可能启用授权。
# Get Access Token for a user.
POST http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/token
{
client_id "<CLIENT_ID>"
client_secret "<CLIENT_SECRET>"
username "<USERNAME>"
password "<USER_PASSWORD>"
grant_type "password"
}
这为我提供了一个访问令牌,我将在以下请求中使用它。
# Try to get access to the resource endpoint
GET http://localhost:8081/api/v1/<resources>
Headers: authorization: Bearer <ACCESS_TOKEN>
这给了我一个符合 UMA2 规范的 401 WWW-Authenticate 和一张票。然后我联系 keycloak 以获得 RPT :
# Get RPT from Keycloak
POST http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/token
Headers: authorization: Bearer <ACCESS_TOKEN>
{
grant_type: "urn:ietf:params:oauth:grant-type:uma-ticket"
ticket: <TICKET>
}
Keycloak 给我一个 RPT,它是一个访问令牌,其中包含权限。然后我重试获取资源,但使用此 RPT
# Try to get access to the resource endpoint
GET http://localhost:8081/api/v1/<resources>
Headers: authorization: Bearer <RPT>
但是适配器没有访问资源,而是再次给我一个 401 WWW-Authenticate。
我深入研究了代码,发现 KeycloakSecurityContext 在 AbstractPolicyEnforcer 中始终为空:
public AuthorizationContext authorize(OIDCHttpFacade httpFacade) {
EnforcementMode enforcementMode = getEnforcerConfig().getEnforcementMode();
// Always return null
KeycloakSecurityContext securityContext = httpFacade.getSecurityContext();
这使得代码每次都被困在这部分代码中:
if (securityContext == null) {
if (!isDefaultAccessDeniedUri(request)) {
if (pathConfig != null) {
if (EnforcementMode.DISABLED.equals(pathConfig.getEnforcementMode())) {
return createEmptyAuthorizationContext(true);
} else {
challenge(pathConfig, getRequiredScopes(pathConfig, request), httpFacade);
}
} else {
handleAccessDenied(httpFacade);
}
}
return createEmptyAuthorizationContext(false);
}
所以我的问题是,经过这么长的解释,为什么没有填充这个 securityContext?我错过了什么吗?
好的,我找到了解决方案。看起来这个适配器想要一个角色的 securityContraints 来完成它的工作。所以我添加这个以使其工作:
keycloak.securityConstraints[0].authRoles[0]=*
keycloak.securityConstraints[0].securityCollections[0].patterns[0]=/*
这基本上告诉它处理所有路径上的所有角色。
P.S 继续使用 JAVA 11,因为它与最新的 JDK 版本不兼容。