如何在 ASP.NET Core 3.0 Preview 5 中将声明映射选项传递给 IdentityServerJwt?
How to pass claims mapping options to IdentityServerJwt in ASP.NET Core 3.0 Preview 5?
受到 an article on custom claims 的启发,我在我的身份服务器登录过程中添加了租户 ID 自定义声明,如下所示:
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using MyNamespace.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using MyNamespace.Data;
using MyNamespace.Constants;
namespace MyNamespace.Factories
{
public class TenantClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
public TenantClaimsPrincipalFactory(
UserManager<ApplicationUser> userManager,
IOptions<IdentityOptions> optionsAccessor)
: base(userManager, optionsAccessor) {
}
// TODO: Remove hard binding to application db context
protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user) {
var identity = await base.GenerateClaimsAsync(user);
var tenantId = ApplicationDbContext.DefaultTenantId;
if (user.TenantId != Guid.Empty) {
tenantId = user.TenantId;
}
identity.AddClaim(new Claim(CustomClaimTypes.TenantId, tenantId.ToString()));
return identity;
}
}
}
声明生成方法在登录时执行,并将声明添加到身份中,所以这部分看起来没问题。后来我尝试在我的租户提供商服务中读出声明如下
using System;
using MyNamespace.Data;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
using System.Linq;
using MyNamespace.Constants;
namespace MyNamespace.Services
{
public interface ITenantProvider
{
Guid GetTenantId();
}
public class TenantProvider : ITenantProvider
{
private IHttpContextAccessor _httpContextAccessor;
public TenantProvider(IHttpContextAccessor httpContextAccessor
{
_httpContextAccessor = httpContextAccessor;
}
// TODO: Remove hard binding to application db context
public Guid GetTenantId()
{
var userId = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
var user = _httpContextAccessor.HttpContext.User;
var tenantId = _httpContextAccessor.HttpContext.User.FindFirst(CustomClaimTypes.TenantId).Value;
Guid tenantGuid = ApplicationDbContext.DefaultTenantId;
Guid.TryParse(tenantId, out tenantGuid);
return tenantGuid;
}
}
}
然而,据我了解,CustomClaimTypes.TenantId
所确定的声明是 not automatically mapped by the Identity server。我的问题是:如何映射
options.ClaimActions.MapUniqueJsonKey(CustomClaimTypes.TenantId, CustomClaimTypes.TenantId);
从 Startup.cs
开始,我将身份服务器添加到我的依赖项中:
services.AddAuthentication()
.AddIdentityServerJwt();
所以,最后我得到了一个与我最初寻求的不同的解决方案。我没有像工厂创建的那样映射声明,而是遇到了 。基本上,我所做的是以下内容。我实施了以下 ProfileService
namespace MyNamespace.Services
{
public class ProfileService : IProfileService
{
protected UserManager<ApplicationUser> _userManager;
public ProfileService(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var user = await _userManager.GetUserAsync(context.Subject);
var claims = new List<Claim>
{
new Claim(CustomClaimTypes.TenantId, user.TenantId.ToString()),
};
context.IssuedClaims.AddRange(claims);
}
public async Task IsActiveAsync(IsActiveContext context)
{
var user = await _userManager.GetUserAsync(context.Subject);
context.IsActive = (user != null) && user.IsActive;
}
}
}
然后,我在 Configure
的 DI 容器中添加了服务:
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>()
.AddProfileService<ProfileService>();
services.AddAuthentication()
.AddIdentityServerJwt();
所以,我仍然乐于让 AddIdentityServerJwt
设置 IdentityServer4,同时获得我的声明。
受到 an article on custom claims 的启发,我在我的身份服务器登录过程中添加了租户 ID 自定义声明,如下所示:
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using MyNamespace.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using MyNamespace.Data;
using MyNamespace.Constants;
namespace MyNamespace.Factories
{
public class TenantClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
public TenantClaimsPrincipalFactory(
UserManager<ApplicationUser> userManager,
IOptions<IdentityOptions> optionsAccessor)
: base(userManager, optionsAccessor) {
}
// TODO: Remove hard binding to application db context
protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user) {
var identity = await base.GenerateClaimsAsync(user);
var tenantId = ApplicationDbContext.DefaultTenantId;
if (user.TenantId != Guid.Empty) {
tenantId = user.TenantId;
}
identity.AddClaim(new Claim(CustomClaimTypes.TenantId, tenantId.ToString()));
return identity;
}
}
}
声明生成方法在登录时执行,并将声明添加到身份中,所以这部分看起来没问题。后来我尝试在我的租户提供商服务中读出声明如下
using System;
using MyNamespace.Data;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
using System.Linq;
using MyNamespace.Constants;
namespace MyNamespace.Services
{
public interface ITenantProvider
{
Guid GetTenantId();
}
public class TenantProvider : ITenantProvider
{
private IHttpContextAccessor _httpContextAccessor;
public TenantProvider(IHttpContextAccessor httpContextAccessor
{
_httpContextAccessor = httpContextAccessor;
}
// TODO: Remove hard binding to application db context
public Guid GetTenantId()
{
var userId = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
var user = _httpContextAccessor.HttpContext.User;
var tenantId = _httpContextAccessor.HttpContext.User.FindFirst(CustomClaimTypes.TenantId).Value;
Guid tenantGuid = ApplicationDbContext.DefaultTenantId;
Guid.TryParse(tenantId, out tenantGuid);
return tenantGuid;
}
}
}
然而,据我了解,CustomClaimTypes.TenantId
所确定的声明是 not automatically mapped by the Identity server。我的问题是:如何映射
options.ClaimActions.MapUniqueJsonKey(CustomClaimTypes.TenantId, CustomClaimTypes.TenantId);
从 Startup.cs
开始,我将身份服务器添加到我的依赖项中:
services.AddAuthentication()
.AddIdentityServerJwt();
所以,最后我得到了一个与我最初寻求的不同的解决方案。我没有像工厂创建的那样映射声明,而是遇到了 ProfileService
namespace MyNamespace.Services
{
public class ProfileService : IProfileService
{
protected UserManager<ApplicationUser> _userManager;
public ProfileService(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var user = await _userManager.GetUserAsync(context.Subject);
var claims = new List<Claim>
{
new Claim(CustomClaimTypes.TenantId, user.TenantId.ToString()),
};
context.IssuedClaims.AddRange(claims);
}
public async Task IsActiveAsync(IsActiveContext context)
{
var user = await _userManager.GetUserAsync(context.Subject);
context.IsActive = (user != null) && user.IsActive;
}
}
}
然后,我在 Configure
的 DI 容器中添加了服务:
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>()
.AddProfileService<ProfileService>();
services.AddAuthentication()
.AddIdentityServerJwt();
所以,我仍然乐于让 AddIdentityServerJwt
设置 IdentityServer4,同时获得我的声明。