我遇到这样的情况:一个Web应用程序需要具有一个声明的访问令牌,而另一个Web应用程序需要另一个声明。
例如,client_1
应该具有声明为is_admin
的访问令牌,而client_2
应该具有声明为stores
的访问令牌。
我想知道-以这种方式在访问令牌中添加此类信息是否正常,还是有更好的选择?
如果要在令牌中添加此信息-您能否建议如何根据客户区分在IProfileService
实现中添加哪个声明?为此目的使用ClientProperties
很好吗?
更新:我使用Azure AD作为外部身份提供者,并且用户没有这些声明-我需要从其他来源检索它
答案 0 :(得分:2)
在您的配置中,添加一个代表客户端应用范围的IdentityResource,例如client_1_scope
,包括IdentityClaim is_admin
。
对client_2_scope
(包括IdentityClaim stores
)执行相同操作。
还允许客户端请求定义的范围(在ClientScopes中添加一条记录)。
在client_1中,像这样请求范围client_1_scope
:
options.Scope.Add("client_1_scope");
在client_2中是这样的:
options.Scope.Add("client_2_scope");
当用户拥有声明is_admin
或stores
时,声明将仅作为请求范围的一部分包含。
添加此行以确保添加了声明:
options.GetClaimsFromUserInfoEndpoint = true;
在client_1应用程序中,配置可能如下所示:
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services
.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.GetClaimsFromUserInfoEndpoint = true;
options.ClaimActions.MapAll();
options.Scope.Add("client_1_scope");
options.Authority = "";
options.ClientId = "";
options.ClientSecret = "";
options.ResponseType = "code id_token";
});
信息将保存在cookie中。如果您希望声明是发送到Api的访问令牌的一部分,则应使用Api〜表来配置声明。
如果这些其他来源已经存在,则可以实现IProfileService,在其中可以根据上述范围添加动态声明,因此仍然需要请求范围。
类似的东西:
using IdentityServer4.Models;
using IdentityServer4.Services;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
public class MyProfileService : IProfileService
{
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
// Include configured claims.
context.AddRequestedClaims(context.Subject.Claims);
// The service gets called multipe times. In this case we need
// the UserInfo endpoint because that's where the scope is defined.
if (context.Caller == "UserInfoEndpoint")
{
// Get the value from somewhere and transform to a list of claims.
// You can filter by requested scopes
List<Claim> userClaims = GetUserClaims(context.RequestedResources.IdentityResources);
if (userClaims.Any())
context.IssuedClaims.AddRange(userClaims);
}
}
public async Task IsActiveAsync(IsActiveContext context)
{
context.IsActive = true;
}
}
如果要向访问令牌(用于api的)添加声明,则context.Caller为ClaimsProviderAccessToken,应查看context.RequestedResources.ApiResources。
在启动时注册服务:
.AddProfileService<MyProfileService>()
请注意,这仅是示例。我没有测试代码。
有单独的资料来源,您也可以查看PolicyServer。在这种情况下,您可以保留IdentityServer进行身份验证,保留PolicyServer进行“选择加入”授权。