Вдохновленный статья о пользовательских претензиях, я добавил пользовательское утверждение идентификатора клиента в процесс входа на сервер Identity следующим образом:
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, является не сопоставляется сервером идентификации автоматически. Мой вопрос заключается в следующем: как я могу отобразить
options.ClaimActions.MapUniqueJsonKey(CustomClaimTypes.TenantId, CustomClaimTypes.TenantId);
из Startup.cs, где я добавляю Identity server в свои зависимости:
services.AddAuthentication()
.AddIdentityServerJwt();





Итак, в конце концов я получил решение, отличное от того, что искал изначально. Вместо сопоставления утверждений, созданных фабрикой, я наткнулся на другой пост здесь, в StackOverflow. В общем, я сделал следующее. Я реализовал следующее 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:
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>()
.AddProfileService<ProfileService>();
services.AddAuthentication()
.AddIdentityServerJwt();
Итак, я все еще хорошо провожу время, позволяя AddIdentityServerJwt настроить IdentityServer4, одновременно получая свои претензии.
@MarkRedman, вы пытаетесь получить доступ к идентификационной информации со стороны сервера? Если вы хотите получить доступ к сеансу пользователя с одного из ваших контроллеров, вы можете использовать var userId = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;. Не забудьте сначала передать IHttpContextAccessor httpContextAccessor в конструкторе вашего контроллера, сохранив ссылку на httpContextAccessor в приватном поле.
У меня нет поступающих претензий (и добавленных вручную в AspNetUserClaims для тестирования). Я просто знаю, что пользователь прошел проверку подлинности, это реализация по умолчанию: docs.microsoft.com/en-us/aspnet/core/security/authentication/… с использованием реакции.
Хм - я не знаю, чувак. Возможно, вам было бы легче помочь, если бы вы написали отдельный вопрос по проблеме, с которой столкнулись, рассказав нам, как вы вручную добавили в AspNetUserClaims и так далее. Дай мне голову, и я посмотрю на это. ;)
Я проведу еще несколько исследований и посмотрю, не пропустил ли я какую-либо дополнительную конфигурацию...
Я начал использовать тот же пример предварительного просмотра, клиентское приложение входит в систему, но я не могу получить информацию об удостоверениях (имя пользователя, утверждения и т. д.). Как мне сослаться на ProfileService и что мне передать для контекста?