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;
前提
我们先看一下这个认证中间件的作用结果,当认证通过时,在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)
{
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;