Identityserver4 Identity Server 4:如何仅为UserInfoEndpoint添加自定义声明并在AccessToken中排除它们?
我们希望从UserInfoEndPoint为用户声明中的大量数据提供服务,但不希望将这些声明嵌入AccessToken中Identityserver4 Identity Server 4:如何仅为UserInfoEndpoint添加自定义声明并在AccessToken中排除它们?,identityserver4,claims,Identityserver4,Claims,我们希望从UserInfoEndPoint为用户声明中的大量数据提供服务,但不希望将这些声明嵌入AccessToken中 public async Task GetProfileDataAsync(ProfileDataRequestContext context) { if (context.Caller != IdentityServerConstants.ProfileDataCallers.ClaimsProviderAccessToken) { var sub
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
if (context.Caller != IdentityServerConstants.ProfileDataCallers.ClaimsProviderAccessToken)
{
var sub = context.Subject.GetSubjectId();
// Get data from Db
var claims = new List<Claim>();
claims.Add(new Claim("global_company_id", "88888888-D964-4A2B-8D56-B893A5BCD700"));
//..... add series of additional claims
context.IssuedClaims = claims;
}
}
据我所知,当我们想要保持AccessToken的小尺寸时,我们可以从UserInfoEndPoint返回额外的数据
因此,我按照以下方式实现了IProfileService:
public class ProfileService : IProfileService
{
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var sub = context.Subject.GetSubjectId();
// Get data from Db
var claims = new List<Claim>();
claims.Add(new Claim("global_company_id", "88888888-D964-4A2B-8D56-B893A5BCD700"));
//..... add series of additional claims
context.IssuedClaims = claims;
}
public async Task IsActiveAsync(IsActiveContext context)
{
var sub = context.Subject.GetSubjectId();
context.IsActive = true;
}
}
以下是我在Identity Server Provider中的客户端配置:
var clientUrl = "http://localhost:64177";
return new Client
{
ClientName = "Test Web Application",
ClientId = "testClientId",
AllowedGrantTypes = GrantTypes.Hybrid,
AllowOfflineAccess = false,
RequireConsent = false,
RedirectUris = new List<string>
{
$"{clientUrl}/signin-oidc"
},
PostLogoutRedirectUris = new List<string>
{
$"{clientUrl}/signout-callback-oidc"
},
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.OfflineAccess,
"t1_global_ids"
},
ClientSecrets =
{
new Secret("abc123".Sha256())
}
};
var clientUrl=”http://localhost:64177";
返回新客户端
{
ClientName=“测试Web应用程序”,
ClientId=“testClientId”,
AllowedGrantTypes=GrantTypes.Hybrid,
AllowOfflineAccess=false,
RequireSent=false,
重定向URI=新列表
{
$“{clientUrl}/signin oidc”
},
PostLogoutRedirectUris=新列表
{
$“{clientUrl}/signout回调oidc”
},
AllowedScopes=新列表
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.OfflineAccess,
“t1_全局_ID”
},
客户秘密=
{
新秘密(“abc123.Sha256())
}
};
这是我连接到Identity Server的MVC.Net核心客户端配置
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies", options =>
{
options.AccessDeniedPath = "/AccessDenied";
})
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://identityserverUrl";
options.ClientId = "testClientId";
options.ResponseType = "code id_token";
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("CustomClaims"); // <-- here
options.SaveTokens = true;
options.ClientSecret = "abc123";
options.GetClaimsFromUserInfoEndpoint = true;
});
services.AddAuthentication(选项=>
{
options.DefaultScheme=“Cookies”;
options.DefaultChallengeScheme=“oidc”;
})
.AddCookie(“Cookies”,选项=>
{
options.AccessDeniedPath=“/AccessDenied”;
})
.AddOpenIdConnect(“oidc”,选项=>
{
options.signnscheme=“Cookies”;
选项。权限=”http://identityserverUrl";
options.ClientId=“testClientId”;
options.ResponseType=“代码id\U令牌”;
options.Scope.Add(“openid”);
选项。范围。添加(“配置文件”);
options.Scope.Add(“CustomClaims”);//我曾经尝试过这个方法,并找到了一个解决方案,但它可能被认为是“黑客式的”——它确实有效,但我从未在生产中使用过,所以使用时要自担风险
ProfileService的GetProfileDataAsync()方法会在不同的时间被调用——当创建JWT时,当点击UserEndpoint时,等等。在这种情况下,您不希望在创建JWT时添加自定义声明,因此创建一个条件,当“调用者”是JWT创建过程(类型为“ClaimsProviderAccessToken”)
公共异步任务GetProfileDataAsync(ProfileDataRequestContext上下文)
{
if(context.Caller!=IdentityServerConstants.ProfileDataCallers.ClaimsProviderAccessToken)
{
var sub=context.Subject.GetSubjectId();
//从数据库获取数据
var索赔=新列表();
添加(新索赔(“全球公司id”,“8888888-D964-4A2B-8D56-B893A5BCD700”);
//……添加一系列附加权利要求
context.IssuedClaims=索赔;
}
}
有了这个,JWT不包含您的自定义声明,但如果您点击UserEndpoint,它将返回这些用户声明作为JSON的一部分。我曾经尝试过这个方法,并找到了一个解决方案,但它可能被认为是“黑客的”——它起作用了,但我从未在生产中使用过,因此使用它的风险由您自己承担 ProfileService的GetProfileDataAsync()方法在不同的时间被调用——当创建JWT时,当点击UserEndpoint时,等等。在这种情况下,您不希望在创建JWT时添加自定义声明,因此创建一个条件,当“调用者”是JWT创建过程(类型为ClaimsProviderAccessToken”) 公共异步任务GetProfileDataAsync(ProfileDataRequestContext上下文) { if(context.Caller!=IdentityServerConstants.ProfileDataCallers.ClaimsProviderAccessToken) { var sub=context.Subject.GetSubjectId(); //从数据库获取数据 var索赔=新列表(); 添加(新索赔(“全球公司id”,“8888888-D964-4A2B-8D56-B893A5BCD700”); //……添加一系列附加权利要求 context.IssuedClaims=索赔; } } 这样,JWT就不包含您的自定义声明,但是如果您点击UserEndpoint,它会将这些用户声明作为JSON的一部分返回
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
if (context.Caller != IdentityServerConstants.ProfileDataCallers.ClaimsProviderAccessToken)
{
var sub = context.Subject.GetSubjectId();
// Get data from Db
var claims = new List<Claim>();
claims.Add(new Claim("global_company_id", "88888888-D964-4A2B-8D56-B893A5BCD700"));
//..... add series of additional claims
context.IssuedClaims = claims;
}
}