net core认证

前提
我们先看一下这个认证中间件的作用结果,当认证通过时,在HttpContext的User属性(ClaimPrincipal)赋予身份标识,所以在后续的请求管道中都是基于认证结果中的身份标识做鉴权,这个我们会在后面的实际操作中会提到。
重要对象讲解
  IAuthenticationSchemeProvider
   从名字来看,IAuthenticationSchemeProvider的作用应该是提供Scheme的,这也是Provider在微软的风格里面起的作用(类似于工厂模式)。仔细看上面这块源码,只有当AuthenticationScheme不为空时才会做认证,否则一旦在Controller打上鉴权标签[Authorize],将会直接返回500,所以我们必须指定自己的Scheme。


一个Scheme对应一个AuthenticationHandler
AuthenticationScheme
属性:
    public string Name { get; }
    public string? DisplayName { get; }
    public Type HandlerType { get; }// 接口继承要求(!typeof(IAuthenticationHandler).IsAssignableFrom(handlerType))

AuthenticationSchemeBuilder
主要方法
public AuthenticationScheme Build()
    {
        if (HandlerType is null)
        {
            throw new InvalidOperationException($"{nameof(HandlerType)} must be configured to build an {nameof(AuthenticationScheme)}.");
        }
        return new AuthenticationScheme(Name, DisplayName, HandlerType);
    }

AuthenticationOptions
主要属性:
private readonly IList<AuthenticationSchemeBuilder> _schemes = new List<AuthenticationSchemeBuilder>();
    /// <summary>
    /// Returns the schemes in the order they were added 
    /// </summary>
   public IEnumerable<AuthenticationSchemeBuilder> Schemes => _schemes;
    public IDictionary<string, AuthenticationSchemeBuilder> SchemeMap { get; } = new Dictionary<string, AuthenticationSchemeBuilder>(StringComparer.Ordinal);
 主要方法:
    public void AddScheme(string name, Action<AuthenticationSchemeBuilder> configureBuilder)
    {
        ArgumentNullException.ThrowIfNull(name);
        ArgumentNullException.ThrowIfNull(configureBuilder);
        if (SchemeMap.ContainsKey(name))
        {
            throw new InvalidOperationException("Scheme already exists: " + name);
        }
        var builder = new AuthenticationSchemeBuilder(name);
        configureBuilder(builder);
        _schemes.Add(builder);
        SchemeMap[name] = builder;
    }

AuthenticationSchemeProvider 
它需要AuthenticationOptions(AuthenticationSchemeBuilder)
构造函数:
protected AuthenticationSchemeProvider(IOptions<AuthenticationOptions> options, IDictionary<string, AuthenticationScheme> schemes)
    {
        _options = options.Value;
        _schemes = schemes ?? throw new ArgumentNullException(nameof(schemes));
        _requestHandlers = new List<AuthenticationScheme>();
 
        foreach (var builder in _options.Schemes)// AuthenticationSchemeBuilder
        {
            var scheme = builder.Build();
            AddScheme(scheme);// _schemes[scheme.Name] = scheme;
        }
    }
属性:
private readonly IDictionary<string, AuthenticationScheme> _schemes;

AuthenticationService
构造函数:
public AuthenticationService(IAuthenticationSchemeProvider schemes, IAuthenticationHandlerProvider handlers, IClaimsTransformation transform, IOptions<AuthenticationOptions> options)
    {
        Schemes = schemes;
        Handlers = handlers;
        Transform = transform;
        Options = options.Value;
    }
主要方法:这几个方法最终都会去IAuthenticationHandler执行而它的来源就是AuthenticationHandlerProvider中根据key获取到的handler。

    /// <summary>
    /// Authenticate for the specified authentication scheme.
    /// </summary>
    /// <param name="context">The <see cref="HttpContext"/>.</param>
    /// <param name="scheme">The name of the authentication scheme.</param>
    /// <returns>The result.</returns>
    public virtual async Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string? scheme)
    {
        if (scheme == null)
        {
            var defaultScheme = await Schemes.GetDefaultAuthenticateSchemeAsync();
            scheme = defaultScheme?.Name;
            if (scheme == null)
            {
                throw new InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultAuthenticateScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).");
            }
        }
 
        var handler = await Handlers.GetHandlerAsync(context, scheme);
        if (handler == null)
        {
            throw await CreateMissingHandlerException(scheme);
        }
 
        // Handlers should not return null, but we'll be tolerant of null values for legacy reasons.
        var result = (await handler.AuthenticateAsync()) ?? AuthenticateResult.NoResult();
 
        if (result.Succeeded)
        {
            var principal = result.Principal!;
            var doTransform = true;
            _transformCache ??= new HashSet<ClaimsPrincipal>();
            if (_transformCache.Contains(principal))
            {
                doTransform = false;
            }
 
            if (doTransform)
            {
                principal = await Transform.TransformAsync(principal);
                _transformCache.Add(principal);
            }
            return AuthenticateResult.Success(new AuthenticationTicket(principal, result.Properties, result.Ticket!.AuthenticationScheme));
        }
        return result;
    }
 
    /// <summary>
    /// Challenge the specified authentication scheme.
    /// </summary>
    /// <param name="context">The <see cref="HttpContext"/>.</param>
    /// <param name="scheme"> authentication scheme.</param>
    /// <param name="properties">.</param>
    /// <returns>A task.</returns>
    public virtual async Task ChallengeAsync(HttpContext context, string? scheme, AuthenticationProperties? properties)
    {
        if (scheme == null)
        {
            var defaultChallengeScheme = await Schemes.GetDefaultChallengeSchemeAsync();
            scheme = defaultChallengeScheme?.Name;
            if (scheme == null)
            {
                throw new InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultChallengeScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).");
            }
        }
 
        var handler = await Handlers.GetHandlerAsync(context, scheme);
        if (handler == null)
        {
            throw await CreateMissingHandlerException(scheme);
        }
 
        await handler.ChallengeAsync(properties);
    }
 
    /// <summary>
    /// Forbid the specified authentication scheme.
    /// </summary>
    /// <param name="context">The <see cref="HttpContext"/>.</param>
    /// <param name="scheme"> the authentication scheme.</param>
    /// <param name="properties">.</param>
    /// <returns>A task.</returns>
    public virtual async Task ForbidAsync(HttpContext context, string? scheme, AuthenticationProperties? properties)
    {
        if (scheme == null)
        {
            var defaultForbidScheme = await Schemes.GetDefaultForbidSchemeAsync();
            scheme = defaultForbidScheme?.Name;
            if (scheme == null)
            {
                throw new InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultForbidScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).");
            }
        }
 
        var handler = await Handlers.GetHandlerAsync(context, scheme);
        if (handler == null)
        {
            throw await CreateMissingHandlerException(scheme);
        }
 
        await handler.ForbidAsync(properties);
    }
 
    /// <summary>
    /// Sign a principal in for the specified authentication scheme.
    /// </summary>
    /// <param name="context">The <see cref="HttpContext"/>.</param>
    /// <param name="scheme"> authentication scheme.</param>
    /// <param name="principal">
    /// <param name="properties">The <see cref="AuthenticationProperties"/>.</param>
    /// <returns>A task.</returns>
    public virtual async Task SignInAsync(HttpContext context, string? scheme, ClaimsPrincipal principal, AuthenticationProperties? properties)
    {
        ArgumentNullException.ThrowIfNull(principal);
 
        if (Options.RequireAuthenticatedSignIn)
        {
            if (principal.Identity == null)
            {
                throw new InvalidOperationException("SignInAsync when principal.Identity == null is not allowed when AuthenticationOptions.RequireAuthenticatedSignIn is true.");
            }
            if (!principal.Identity.IsAuthenticated)
            {
                throw new InvalidOperationException("SignInAsync when principal.Identity.IsAuthenticated is false is not allowed when AuthenticationOptions.RequireAuthenticatedSignIn is true.");
            }
        }
 
        if (scheme == null)
        {
            var defaultScheme = await Schemes.GetDefaultSignInSchemeAsync();
            scheme = defaultScheme?.Name;
            if (scheme == null)
            {
                throw new InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultSignInScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).");
            }
        }
 
        var handler = await Handlers.GetHandlerAsync(context, scheme);
        if (handler == null)
        {
            throw await CreateMissingSignInHandlerException(scheme);
        }
 
        var signInHandler = handler as IAuthenticationSignInHandler;
        if (signInHandler == null)
        {
            throw await CreateMismatchedSignInHandlerException(scheme, handler);
        }
 
        await signInHandler.SignInAsync(principal, properties);
    }
 
    /// <summary>
    /// Sign out the specified authentication scheme.
    /// </summary>
    /// <param name="context">The <see cref="HttpContext"/>.</param>
    /// <param name="scheme"> authentication scheme.</param>
    /// <param name="properties"> </param>
    /// <returns>A task.</returns>
    public virtual async Task SignOutAsync(HttpContext context, string? scheme, AuthenticationProperties? properties)
    {
        if (scheme == null)
        {
            var defaultScheme = await Schemes.GetDefaultSignOutSchemeAsync();
            scheme = defaultScheme?.Name;
            if (scheme == null)
            {
                throw new InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultSignOutScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).");
            }
        }
 
        var handler = await Handlers.GetHandlerAsync(context, scheme);
        if (handler == null)
        {
            throw await CreateMissingSignOutHandlerException(scheme);
        }
 
        var signOutHandler = handler as IAuthenticationSignOutHandler;
        if (signOutHandler == null)
        {
            throw await CreateMismatchedSignOutHandlerException(scheme, handler);
        }
 
        await signOutHandler.SignOutAsync(properties);
}


AuthenticationMiddleware
认证处理的中间件
属性
private readonly RequestDelegate _next;
构造函数
public AuthenticationMiddleware(RequestDelegate next, IAuthenticationSchemeProvider schemes)
{
        ArgumentNullException.ThrowIfNull(next);
        ArgumentNullException.ThrowIfNull(schemes);
 
        _next = next;
        Schemes = schemes;
}
-主要方法-
public async Task Invoke(HttpContext context)
{
        context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature
        {
            OriginalPath = context.Request.Path,
            OriginalPathBase = context.Request.PathBase
        });
 
        // Give any IAuthenticationRequestHandler schemes a chance to handle the request
        var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
        foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
        {
            var handler = await handlers.GetHandlerAsync(context, scheme.Name) as IAuthenticationRequestHandler;
            if (handler != null && await handler.HandleRequestAsync())
            {
                return;
            }
        }
        var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
        if (defaultAuthenticate != null)
        {
            var result = await context.AuthenticateAsync(defaultAuthenticate.Name);
            if (result?.Principal != null)
            {
                context.User = result.Principal;
            }
            if (result?.Succeeded ?? false)
            {
                var authFeatures = new AuthenticationFeatures(result);
                context.Features.Set<IHttpAuthenticationFeature>(authFeatures);
                context.Features.Set<IAuthenticateResultFeature>(authFeatures);
            }
        }
 
        await _next(context);
    }
--
看一下handler. GetHandlerAsync ()这个方法,根据scheme获取handler
public async Task<IAuthenticationHandler?> GetHandlerAsync(HttpContext context, string authenticationScheme)
    {
        if (_handlerMap.TryGetValue(authenticationScheme, out var value))
        {
            return value;
        }
        var scheme = await Schemes.GetSchemeAsync(authenticationScheme);
        if (scheme == null)
        {
            return null;
        }
        var handler = (context.RequestServices.GetService(scheme.HandlerType) ??
            ActivatorUtilities.CreateInstance(context.RequestServices, scheme.HandlerType))
            as IAuthenticationHandler;
        if (handler != null)
        {
            await handler.InitializeAsync(scheme, context);
            _handlerMap[authenticationScheme] = handler;// 存起来防止重复使用
        }
        return handler;
    }
 还有context.AuthenticateAsync最终是调用AuthenticationService. AuthenticateAsync源码如下:
public virtual async Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string? scheme)
    {
        if (scheme == null)
        {
            var defaultScheme = await Schemes.GetDefaultAuthenticateSchemeAsync();
            scheme = defaultScheme?.Name;
            if (scheme == null)
            {
                throw new InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultAuthenticateScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).");
            }
        }
 
        var handler = await Handlers.GetHandlerAsync(context, scheme);
        if (handler == null)
        {
            throw await CreateMissingHandlerException(scheme);
        }
 
        // Handlers should not return null, but we'll be tolerant of null values for legacy reasons.
        var result = (await handler.AuthenticateAsync()) ?? AuthenticateResult.NoResult();
 
        if (result.Succeeded)
        {
            var principal = result.Principal!;
            var doTransform = true;
            _transformCache ??= new HashSet<ClaimsPrincipal>();
            if (_transformCache.Contains(principal))
            {
                doTransform = false;
            }
 
            if (doTransform)
            {
                principal = await Transform.TransformAsync(principal);
                _transformCache.Add(principal);
            }
            return AuthenticateResult.Success(new AuthenticationTicket(principal, result.Properties, result.Ticket!.AuthenticationScheme));
        }
        return result;
}
--
handler.InitializeAsync源码如下:运行了具体子类中的
    await InitializeEventsAsync();
await InitializeHandlerAsync();

AuthenticateResult
关键属性:
public Exception? Failure { get; protected set; }
public AuthenticationTicket? Ticket { get; protected set; }
public ClaimsPrincipal? Principal => Ticket?.Principal;
public bool Succeeded => Ticket != null;

 

前提

我们先看一下这个认证中间件的作用结果,当认证通过时,在HttpContextUser属性(ClaimPrincipal)赋予身份标识,所以在后续的请求管道中都是基于认证结果中的身份标识做鉴权,这个我们会在后面的实际操作中会提到。

重要对象讲解

  IAuthenticationSchemeProvider

   从名字来看,IAuthenticationSchemeProvider的作用应该是提供Scheme的,这也是Provider在微软的风格里面起的作用(类似于工厂模式)。仔细看上面这块源码,只有当AuthenticationScheme不为空时才会做认证,否则一旦在Controller打上鉴权标签[Authorize],将会直接返回500,所以我们必须指定自己的Scheme

 

 

一个Scheme对应一个AuthenticationHandler

AuthenticationScheme

属性:
        public string Name { get; }
        public string? DisplayName { get; }
public Type HandlerType { get; }// 接口继承要求(!typeof(IAuthenticationHandler).IsAssignableFrom(handlerType))

 

AuthenticationSchemeBuilder

主要方法

public AuthenticationScheme Build()
    {
        if (HandlerType is null)
        {
            thrownew InvalidOperationException($"{nameof(HandlerType)} must be configured to build an {nameof(AuthenticationScheme)}.");
        }
        returnnew AuthenticationScheme(Name, DisplayName, HandlerType);
    }

 

AuthenticationOptions

主要属性:

private readonly IList<AuthenticationSchemeBuilder> _schemes = new List<AuthenticationSchemeBuilder>();
    /// <summary>
    /// Returns the schemes in the order they were added 
    /// </summary>
   public IEnumerable<AuthenticationSchemeBuilder> Schemes => _schemes;
   public IDictionary<string, AuthenticationSchemeBuilder> SchemeMap { get; } = new Dictionary<string, AuthenticationSchemeBuilder>(StringComparer.Ordinal);
主要方法:
   public void AddScheme(string name, Action<AuthenticationSchemeBuilder> configureBuilder)
    {
        ArgumentNullException.ThrowIfNull(name);
        ArgumentNullException.ThrowIfNull(configureBuilder);
        if (SchemeMap.ContainsKey(name))
        {
            thrownew InvalidOperationException("Scheme already exists: " + name);
        }
        var builder = new AuthenticationSchemeBuilder(name);
        configureBuilder(builder);
        _schemes.Add(builder);
        SchemeMap[name] = builder;
    }

 

AuthenticationSchemeProvider

它需要AuthenticationOptions(AuthenticationSchemeBuilder)

构造函数:

protected AuthenticationSchemeProvider(IOptions<AuthenticationOptions> options, IDictionary<string, AuthenticationScheme> schemes)
    {
        _options = options.Value;
        _schemes = schemes ?? thrownew ArgumentNullException(nameof(schemes));
        _requestHandlers = new List<AuthenticationScheme>();

        foreach (var builder in _options.Schemes)//AuthenticationSchemeBuilder
        {
            var scheme = builder.Build();
            AddScheme(scheme);// _schemes[scheme.Name] = scheme;
        }
    }

属性:

private readonly IDictionary<string, AuthenticationScheme> _schemes;

 

AuthenticationService

构造函数:

public AuthenticationService(IAuthenticationSchemeProvider schemes, IAuthenticationHandlerProvider handlers, IClaimsTransformation transform, IOptions<AuthenticationOptions> options)
    {
        Schemes = schemes;
        Handlers = handlers;
        Transform = transform;
        Options = options.Value;
    }
主要方法:这几个方法最终都会去IAuthenticationHandler执行而它的来源就是AuthenticationHandlerProvider中根据key获取到的handler
 

    /// <summary>

    /// Authenticate for the specified authentication scheme.

    /// </summary>

    /// <paramname="context">The <seecref="HttpContext"/>.</param>

    /// <paramname="scheme">The name of the authentication scheme.</param>

    /// <returns>The result.</returns>

    public virtual async Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string? scheme)

    {

        if (scheme == null)

        {

            var defaultScheme = await Schemes.GetDefaultAuthenticateSchemeAsync();

            scheme = defaultScheme?.Name;

            if (scheme == null)

            {

                thrownew InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultAuthenticateScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).");

            }

        }

 

        var handler = await Handlers.GetHandlerAsync(context, scheme);

        if (handler == null)

        {

            throwawait CreateMissingHandlerException(scheme);

        }

 

        // Handlers should not return null, but we'll be tolerant of null values for legacy reasons.

        var result = (await handler.AuthenticateAsync()) ?? AuthenticateResult.NoResult();

 

        if (result.Succeeded)

        {

            var principal = result.Principal!;

            var doTransform = true;

            _transformCache ??= new HashSet<ClaimsPrincipal>();

            if (_transformCache.Contains(principal))

            {

                doTransform = false;

            }

 

            if (doTransform)

            {

                principal = await Transform.TransformAsync(principal);

                _transformCache.Add(principal);

            }

            return AuthenticateResult.Success(new AuthenticationTicket(principal, result.Properties, result.Ticket!.AuthenticationScheme));

        }

        return result;

    }

 

    /// <summary>

    /// Challenge the specified authentication scheme.

    /// </summary>

    /// <paramname="context">The <seecref="HttpContext"/>.</param>

    /// <paramname="scheme"> authentication scheme.</param>

    /// <paramname="properties">.</param>

    /// <returns>A task.</returns>

    public virtual async Task ChallengeAsync(HttpContext context, string? scheme, AuthenticationProperties? properties)

    {

        if (scheme == null)

        {

            var defaultChallengeScheme = await Schemes.GetDefaultChallengeSchemeAsync();

            scheme = defaultChallengeScheme?.Name;

            if (scheme == null)

            {

                thrownew InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultChallengeScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).");

            }

        }

 

        var handler = await Handlers.GetHandlerAsync(context, scheme);

        if (handler == null)

        {

            throwawait CreateMissingHandlerException(scheme);

        }

 

        await handler.ChallengeAsync(properties);

    }

 

    /// <summary>

    /// Forbid the specified authentication scheme.

    /// </summary>

    /// <paramname="context">The <seecref="HttpContext"/>.</param>

    /// <paramname="scheme"> the authentication scheme.</param>

    /// <paramname="properties">.</param>

    /// <returns>A task.</returns>

    public virtual async Task ForbidAsync(HttpContext context, string? scheme, AuthenticationProperties? properties)

    {

        if (scheme == null)

        {

            var defaultForbidScheme = await Schemes.GetDefaultForbidSchemeAsync();

            scheme = defaultForbidScheme?.Name;

            if (scheme == null)

            {

                thrownew InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultForbidScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).");

            }

        }

 

        var handler = await Handlers.GetHandlerAsync(context, scheme);

        if (handler == null)

        {

            throwawait CreateMissingHandlerException(scheme);

        }

 

        await handler.ForbidAsync(properties);

    }

 

    /// <summary>

    /// Sign a principal in for the specified authentication scheme.

    /// </summary>

    /// <paramname="context">The <seecref="HttpContext"/>.</param>

    /// <paramname="scheme"> authentication scheme.</param>

    /// <paramname="principal">

    /// <paramname="properties">The <seecref="AuthenticationProperties"/>.</param>

    /// <returns>A task.</returns>

    public virtual async Task SignInAsync(HttpContext context, string? scheme, ClaimsPrincipal principal, AuthenticationProperties? properties)

    {

        ArgumentNullException.ThrowIfNull(principal);

 

        if (Options.RequireAuthenticatedSignIn)

        {

            if (principal.Identity == null)

            {

                thrownew InvalidOperationException("SignInAsync when principal.Identity == null is not allowed when AuthenticationOptions.RequireAuthenticatedSignIn is true.");

            }

            if (!principal.Identity.IsAuthenticated)

            {

                thrownew InvalidOperationException("SignInAsync when principal.Identity.IsAuthenticated is false is not allowed when AuthenticationOptions.RequireAuthenticatedSignIn is true.");

            }

        }

 

        if (scheme == null)

        {

            var defaultScheme = await Schemes.GetDefaultSignInSchemeAsync();

            scheme = defaultScheme?.Name;

            if (scheme == null)

            {

                thrownew InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultSignInScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).");

            }

        }

 

        var handler = await Handlers.GetHandlerAsync(context, scheme);

        if (handler == null)

        {

            throwawait CreateMissingSignInHandlerException(scheme);

        }

 

        var signInHandler = handler as IAuthenticationSignInHandler;

        if (signInHandler == null)

        {

            throwawait CreateMismatchedSignInHandlerException(scheme, handler);

        }

 

        await signInHandler.SignInAsync(principal, properties);

    }

 

    /// <summary>

    /// Sign out the specified authentication scheme.

    /// </summary>

    /// <paramname="context">The <seecref="HttpContext"/>.</param>

    /// <paramname="scheme"> authentication scheme.</param>

    /// <paramname="properties"> </param>

    /// <returns>A task.</returns>

    public virtual async Task SignOutAsync(HttpContext context, string? scheme, AuthenticationProperties? properties)

    {

        if (scheme == null)

        {

            var defaultScheme = await Schemes.GetDefaultSignOutSchemeAsync();

            scheme = defaultScheme?.Name;

            if (scheme == null)

            {

                thrownew InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultSignOutScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).");

            }

        }

 

        var handler = await Handlers.GetHandlerAsync(context, scheme);

        if (handler == null)

        {

            throwawait CreateMissingSignOutHandlerException(scheme);

        }

 

        var signOutHandler = handler as IAuthenticationSignOutHandler;

        if (signOutHandler == null)

        {

            throwawait CreateMismatchedSignOutHandlerException(scheme, handler);

        }

 

        await signOutHandler.SignOutAsync(properties);

}

 

 

AuthenticationMiddleware

认证处理的中间件

属性

private readonly RequestDelegate _next;

构造函数

public AuthenticationMiddleware(RequestDelegate next, IAuthenticationSchemeProvider schemes)
{
        ArgumentNullException.ThrowIfNull(next);
        ArgumentNullException.ThrowIfNull(schemes);

        _next = next;
        Schemes = schemes;
}

-主要方法-

public async Task Invoke(HttpContext context)
{
        context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature
        {
            OriginalPath = context.Request.Path,
            OriginalPathBase = context.Request.PathBase
        });

        // Give any IAuthenticationRequestHandler schemes a chance to handle the request
        var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
        foreach (var scheme inawait Schemes.GetRequestHandlerSchemesAsync())
        {
            var handler = await handlers.GetHandlerAsync(context, scheme.Name) as IAuthenticationRequestHandler;
            if (handler != null && await handler.HandleRequestAsync())
            {
                return;
            }
        }
        var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
        if (defaultAuthenticate != null)
        {
            var result = await context.AuthenticateAsync(defaultAuthenticate.Name);
            if (result?.Principal != null)
            {
                context.User = result.Principal;
            }
            if (result?.Succeeded ?? false)
            {
                var authFeatures = new AuthenticationFeatures(result);
                context.Features.Set<IHttpAuthenticationFeature>(authFeatures);
                context.Features.Set<IAuthenticateResultFeature>(authFeatures);
            }
        }

        await _next(context);
    }

--

看一下handler. GetHandlerAsync ()这个方法,根据scheme获取handler
public async Task<IAuthenticationHandler?> GetHandlerAsync(HttpContext context, string authenticationScheme)
    {
        if (_handlerMap.TryGetValue(authenticationScheme, out var value))
        {
            return value;
        }
        var scheme = await Schemes.GetSchemeAsync(authenticationScheme);
        if (scheme == null)
        {
            returnnull;
        }
        var handler = (context.RequestServices.GetService(scheme.HandlerType) ??
            ActivatorUtilities.CreateInstance(context.RequestServices, scheme.HandlerType))
            as IAuthenticationHandler;
        if (handler != null)
        {
            await handler.InitializeAsync(scheme, context);
            _handlerMap[authenticationScheme] = handler;// 存起来防止重复使用
        }
        return handler;
    }
还有context.AuthenticateAsync最终是调用AuthenticationService. AuthenticateAsync源码如下:
public virtual async Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string? scheme)
    {
        if (scheme == null)
        {
            var defaultScheme = await Schemes.GetDefaultAuthenticateSchemeAsync();
            scheme = defaultScheme?.Name;
            if (scheme == null)
            {
                thrownew InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultAuthenticateScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).");
            }
        }

        var handler = await Handlers.GetHandlerAsync(context, scheme);
        if (handler == null)
        {
            throwawait CreateMissingHandlerException(scheme);
        }

        // Handlers should not return null, but we'll be tolerant of null values for legacy reasons.
        var result = (await handler.AuthenticateAsync()) ?? AuthenticateResult.NoResult();

        if (result.Succeeded)
        {
            var principal = result.Principal!;
            var doTransform = true;
            _transformCache ??= new HashSet<ClaimsPrincipal>();
            if (_transformCache.Contains(principal))
            {
                doTransform = false;
            }

            if (doTransform)
            {
                principal = await Transform.TransformAsync(principal);
                _transformCache.Add(principal);
            }
            return AuthenticateResult.Success(new AuthenticationTicket(principal, result.Properties, result.Ticket!.AuthenticationScheme));
        }
        return result;
}
--
handler.InitializeAsync源码如下:运行了具体子类中的

    await InitializeEventsAsync();

await InitializeHandlerAsync();

 

AuthenticateResult

关键属性:
public Exception? Failure { get; protected set; }
public AuthenticationTicket? Ticket { get; protected set; }
public ClaimsPrincipal? Principal => Ticket?.Principal;
public bool Succeeded => Ticket != null;
 
 
 

 

posted @ 2023-05-25 15:22  vba是最好的语言  阅读(146)  评论(0编辑  收藏  举报