Asp. net Core 3.1, преобразовывающий ClaimsIdentity с несколькими AuthenticationScheme - PullRequest
1 голос
/ 17 апреля 2020

Я столкнулся с проблемой при реализации нескольких схем авторизации в ASP. Net Базовом приложении. Допустим, они объявлены так в Startup.cs

public void ConfigureServices(IServiceCollection services)
{
      AuthenticationBuilder builder = services
                .AddAuthentication()
                .AddBasicAuthentication(o => { o.Realm = "MyRealm"; })
                .AddApiKeyAuthentication()
                .AddBearerToken(opt => { });
}

Каждая из этих схем обеспечивает собственную реализацию AuthenticationHandler , возвращающую ClaimsIdentity в случае успеха. Но в каждом случае структура претензий является незаметной, т.е. ApiKeyAuthentication может вернуть ClaimsIdentity с данными, чувствительными к бизнесу, которые хранятся в претензии "api_service", в то время как BearerTokenScheme сохранит их в подпункте претензии, а я не имею контроля через это. Поэтому, если я хотел бы использовать эту информацию в контроллере, чтобы связать некоторый процесс со службой, которая вызвала мой метод API, я должен реализовать несколько сложных логик c, которые бы анализировали текущий ClaimsIdentity , его аутентификацию Схема и набор требований. Вместо этого я хотел бы реализовать некую трансформацию ClaimsIdentity в MyServiceClaimsIdentity , которая бы выявила заявки удобным способом, чтобы я мог легко использовать их в своем коде контроллеров:

public class MyServiceClaimsIdentity: IIdentity
{
    private readonly ClaimsIdentity innerIdentity;
    public Guid? UserId {get; }
    public string UserName {get; }
    public string ServiceName {get; }

    public MyServiceClaimsIdentity(ClaimsIdentity identity)
    {
        this.innerIdentity = identity;
        TransformClaimsIntoProperties();
    }

    private void TransformClaimsIntoProperties()
    {
        ......
    }
}

I ' мы пытались реализовать некий «преобразующий» AuthenticationHandler , который мог бы выдать MyServiceClaimsIdentity после того, как все другие обработчики выдадут свой ClaimsIdentity.

public class FinalAuthenticationHandler : AuthenticationHandler<FinalAuthenticationOptions>
    {
        public FinalAuthenticationHandler(
            IOptionsMonitor<FinalAuthenticationOptions> options,
            ILoggerFactory logger,
            UrlEncoder encoder,
            ISystemClock clock)
            : base(options, logger, encoder, clock)
        {
        }

        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            if (!this.Context.User.Identity.IsAuthenticated)
            {
                return null;
            }

            var identity = new MyServiceClaimsIdentity(this.Context.User.Identity);
            var principal = new ClaimsPrincipal(identity);
            var ticket = new AuthenticationTicket(principal, this.Scheme.Name);
            return AuthenticateResult.Success(ticket);
        }
    }

Слишком плохо на этом этапе this.Context.User.Identity не содержит никакой информации о пользователе, поэтому я не понимаю, куда поместить этот лог трансформации c или как мне получить текущий ClaimsIdentity, предоставленный другим обработчиком, в моем FinalAuthenticationHandler . Любая помощь будет оценена.

1 Ответ

0 голосов
/ 17 апреля 2020

Реализация преобразования IClaimsTransformation и его регистрация в качестве синглтона отлично сработали

internal sealed class ClaimsTransformation : IClaimsTransformation
    {
        private readonly IDictionary<string, IClaimsHandler> handlersMap;

        public ClaimsTransformation(IEnumerable<IClaimsHandler> handlers)
        {
            if (handlers == null)
            {
                throw new ArgumentNullException(nameof(handlers));
            }

            this.handlersMap = handlers.ToDictionary(t => t.SchemeName);
        }

        public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
        {
            if (!(principal.Identity is ClaimsIdentity claimsIdentity))
            {
                throw new InvalidOperationException($"Principal.Identity is of type {principal.Identity.GetType()}, expected ClaimsIdentity");
            }

            if (!this.handlersMap.TryGetValue(principal.Identity.AuthenticationType, out var handler))
            {
                throw new AuthenticationException($"Scheme of type {principal.Identity.AuthenticationType} is not supported");
            }

            var result = new ClaimsPrincipal(handler.Handle(claimsIdentity));
            return Task.FromResult(result);
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...