【问题标题】:Keycloak - large tokens - lazy role evaluationKeycloak - 大令牌 - 懒惰的角色评估
【发布时间】:2021-11-27 11:15:50
【问题描述】:

我目前使用 Keycloak (v11) 作为身份代理来进行身份验证和授权。我面临的一个问题是,如果用户具有多个角色,Keycloak 生成的 JWT 令牌往往会变得非常大。目前,使用 Keycloak 进行身份代理的项目由多个微服务(客户端,在 Keycloak 术语中)组成。这导致我提出两个问题:

  1. 为什么特定的客户端/资源请求 JWT, JWT 附带该用户的所有客户端角色(包括客户端 其他客户的角色)?它会破坏 Open ID 中的任何模式吗 如果我更改了默认客户端范围,则连接,以便只有 会出现与客户相关的特定客户角色?或者会 该特定模式有不同的名称吗?
  2. 是否存在与 OIDC 相关的模式,即首先进行身份验证,然后“延迟评估”与授权相关的问题,例如角色?也就是说,我希望某个代理 Bob 通过 Keycloak 进行身份验证,并且每当 Bob 想要使用某个受角色保护的服务时,Bob 都会询问 Keycloak 他是否具有该特定角色。这样做的目的是最小化令牌大小。

【问题讨论】:

  • 我猜您在 Keycloak 中的客户端配置不正确。为什么不将客户端配置为仅返回与该特定客户端相关的角色?客户端级别有许多配置选项。盲目猜测(因为你没有发布任何配置)Full Scope AllowedON
  • 'Full Scope Allowed' OFF 表示什么?
  • Full Scope Allowed: OFF = 您可以为每个客户明确选择所需的角色; Full Scope Allowed: ON = 客户端隐式获取用户的所有角色映射。见文档:keycloak.org/docs/latest/server_admin/…
  • 我试过了,它似乎并没有改变行为。可能是因为客户端角色是根据复合角色定义的,因此它们会自动从某个领域角色继承。
  • 有很多配置选项,这只是其中之一。你没有展示你是如何配置你的客户端的,所以一切都只是猜测。不幸的是,我不想玩猜谜游戏。只是提示(但如果它们不适合您的情况,请不要怪我 - 再次只是猜测):范围,映射器,LDAP 过滤器,.....

标签: oauth-2.0 keycloak openid-connect openid keycloak-services


【解决方案1】:

我最终制作了自己的自定义 Keycloak ProtocolMapper,它从默认的 UserClientRoleMappingMapper 扩展而来。诀窍是通过 setClaim 方法中的 ClientSessionContext 获取“clientId”。默认的 UserClientRoleMappingMapper 允许相同的功能,但您必须在映射器实例中手动指定 clientId。由于现在这是自动完成的,因此我在“CONFIG_PROPERTIES”中删除了此选项。

import org.keycloak.models.ClientSessionContext;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.ProtocolMapperUtils;
import org.keycloak.protocol.oidc.mappers.UserClientRoleMappingMapper;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.IDToken;
import org.keycloak.utils.RoleResolveUtil;

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

public class UserClientRoleMapper extends UserClientRoleMappingMapper {

    public static final String MAPPER_PROVIDER_ID = "oidc-client-role-mapper-scoped";

    private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = new ArrayList<>();

    @Override
    public List<ProviderConfigProperty> getConfigProperties() {
        if (CONFIG_PROPERTIES.size() > 0) {
            return CONFIG_PROPERTIES;
        }
        CONFIG_PROPERTIES.addAll(super.getConfigProperties());
        CONFIG_PROPERTIES.removeIf(property -> property.getName().equals(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID));
        return CONFIG_PROPERTIES;
    }

    @Override
    public String getId() {
        return MAPPER_PROVIDER_ID;
    }

    @Override
    public String getDisplayType() {
        return "User Client Role Scoped";
    }

    @Override
    public String getHelpText() {
        return "Map a user client role to a token claim.";
    }

    @Override
    protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession, KeycloakSession session, ClientSessionContext clientSessionCtx) {
        String clientId = clientSessionCtx.getClientSession().getClient().getClientId();
        String rolePrefix = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX);

        if (clientId != null && !clientId.isEmpty()) {
            AccessToken.Access access = RoleResolveUtil.getResolvedClientRoles(session, clientSessionCtx, clientId, false);
            if (access == null) {
                return;
            }

            UserClientRoleMappingMapper.setClaim(token, mappingModel, access.getRoles(), clientId, rolePrefix);
        }
    }

}

【讨论】:

    猜你喜欢
    • 2019-01-07
    • 1970-01-01
    • 2015-09-06
    • 2016-12-14
    • 2021-12-25
    • 2018-04-01
    • 2018-03-31
    • 1970-01-01
    • 2017-04-30
    相关资源
    最近更新 更多