如何从userinfo端点获取声明,而不将它们包含在id token

时间:2017-09-12 13:05:05

标签: openid identityserver4 oidc

我在试图弄清楚如何正确使用userinfo端点时遇到了麻烦。我的示例使用身份服务器4作为授权服务器。

假设我有一个显示经过身份验证的用户位置的js应用程序。我们假设我有一些用户商店提供包括用户位置在内的声明。已实现iprofileservice接口,以便GetProfileDataAsync从用户存储中为用户检索用户声明。

js app需要有权访问用户的位置声明。一种方法是将标识符添加到ids,例如

new IdentityResource("test", new [] {"location"})

然后将范围添加到js客户端,例如

new Client
{
    ClientId = "js",
    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        "test"
    }
}

然后配置oidc库以请求该范围,例如

var config = {
   authority: "http://localhost:5000",
   client_id: "js",
   redirect_uri: "http://localhost:5003/callback.html",
   response_type: "id_token token",
   scope:"openid test",
   post_logout_redirect_uri : "http://localhost:5003/index.html",
};

这样做意味着id_token将包含位置声明,并且这可以作为用户配置文件的一部分进行访问。在使用在身份验证期间收到的访问令牌调用userinfo端点时,将返回相同的声明。

但是我反复阅读(here, for instance)您应该尽可能少地声明身份令牌,然后使用userinfo端点来检索其他声明。链接的文章似乎暗示默认情况下在身份服务器中可以使用此行为。

所以为了做到这一点,使用上面提到的示例代码,我将从oidc配置的请求范围中删除'test'范围。这意味着将不再使用位置声明填充id令牌。但是,当调用userinfo端点时,“测试”范围不在访问令牌中,因此位置声明不会放入响应中。

基本上我的问题是你应该如何要求从id令牌中省略声明,但是从userinfo端点返回?

oidc规范似乎也暗示您应该能够使用“声明”请求参数请求特定声明,但我无法找到任何有关身份服务器(或auth0)的文档物质)。

2 个答案:

答案 0 :(得分:1)

如果您仅请求身份令牌,则所有声明都将在该令牌中。如果同时请求id_token和令牌,则只有基本声明将在id_token中,并且可以从userinfo端点检索所有其他声明。

这是规范建议的。

https://leastprivilege.com/2016/12/14/optimizing-identity-tokens-for-size/

答案 1 :(得分:0)

我实现这一目标的一种方法是使用IdentityResourceApiResource

例如,在您的创业公司> ConfigureServices

    services.AddIdentityServer(x =>
        {
            x.IssuerUri = webServerSettings.Host;
        })
        .AddSigningCredential(webServerSettings.CertificateSubjectDn)
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryIdentityResources(Config.GetIdentityResources());

然后在我的配置中为GetApiResources提供了类似的内容:

public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource
                {
                    Name = "MyApi",
                    ApiSecrets = { new Secret("somesecret".Sha256()) },
                    UserClaims = {
                        JwtClaimTypes.GivenName,
                        JwtClaimTypes.FamilyName,
                        JwtClaimTypes.PreferredUserName
                    },
                    Description = "some description",
                    DisplayName = "my api display name",
                    Enabled = true,
                    Scopes = { new Scope("MyApiScope") }
                },

                new ApiResource("otherAPI", "Some other API"),
            };
        }

但也有GetIdentityResources

public static IEnumerable<IdentityResource> GetIdentityResources()
    {
        return new List<IdentityResource>
        {
            new IdentityResources.OpenId(),
            // The identity scope defines the claims available at the client by calling the 
            // userinfo endpoint, and does not need to match the claims available to the API
            // which are defined as part of the ApiResource above
            new IdentityResource
            {
                Name = "MyApiIdentityScope",
                UserClaims = {
                    JwtClaimTypes.Email,
                    JwtClaimTypes.EmailVerified,
                    JwtClaimTypes.PhoneNumber,
                    JwtClaimTypes.PhoneNumberVerified,
                    JwtClaimTypes.GivenName,
                    JwtClaimTypes.FamilyName,
                    JwtClaimTypes.PreferredUserName
                }
            }
        };
    }

通过执行此操作,对GetProfileDataAsync的调用将具有不同的RequestedClaimTypes,具体取决于它是通过UserInfo端点传递还是仅来自对令牌的请求。