如何从 userinfo 端点获取声明而不将它们包含在 id 令牌中
how to get claims from userinfo endpoint without including them in id token
我在尝试弄清楚如何正确使用 userinfo 端点时遇到了问题。我的示例使用身份服务器 4 作为授权服务器。
假设我有一个显示经过身份验证的用户位置的 js 应用程序。让我们假设我有一些用户存储,它提供包括用户位置在内的声明。已实现 iprofileservice 接口,以便 GetProfileDataAsync 从用户存储中为用户检索用户声明。
js 应用程序需要访问用户的位置声明。一种方法是向 ID 添加身份资源,例如
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 端点时,'test' 范围不在访问令牌中,因此不会将位置声明放入响应中。
基本上我的问题是你应该如何要求从 id 令牌中省略声明,但从 userinfo 端点返回?
oidc 规范似乎还暗示您应该能够使用“claims”请求参数来请求特定声明,但我找不到有关身份服务器的任何文档(或 auth0 就此而言)。
我实现此目的的一种方法是使用 IdentityResource
与 ApiResource
。
例如,在您的启动 > 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 端点还是仅来自令牌请求。
如果您只请求身份令牌,所有声明都将在该令牌中。如果您同时请求 id_token 和令牌,则只有基本声明会在 id_token 中,所有其他声明都可以从 userinfo 端点检索。
这是规范建议的。
https://leastprivilege.com/2016/12/14/optimizing-identity-tokens-for-size/
我在尝试弄清楚如何正确使用 userinfo 端点时遇到了问题。我的示例使用身份服务器 4 作为授权服务器。
假设我有一个显示经过身份验证的用户位置的 js 应用程序。让我们假设我有一些用户存储,它提供包括用户位置在内的声明。已实现 iprofileservice 接口,以便 GetProfileDataAsync 从用户存储中为用户检索用户声明。
js 应用程序需要访问用户的位置声明。一种方法是向 ID 添加身份资源,例如
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 端点时,'test' 范围不在访问令牌中,因此不会将位置声明放入响应中。
基本上我的问题是你应该如何要求从 id 令牌中省略声明,但从 userinfo 端点返回?
oidc 规范似乎还暗示您应该能够使用“claims”请求参数来请求特定声明,但我找不到有关身份服务器的任何文档(或 auth0 就此而言)。
我实现此目的的一种方法是使用 IdentityResource
与 ApiResource
。
例如,在您的启动 > 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 端点还是仅来自令牌请求。
如果您只请求身份令牌,所有声明都将在该令牌中。如果您同时请求 id_token 和令牌,则只有基本声明会在 id_token 中,所有其他声明都可以从 userinfo 端点检索。
这是规范建议的。
https://leastprivilege.com/2016/12/14/optimizing-identity-tokens-for-size/