asp.net core 3.0认证详解
整体概况
这篇文章前前后后改了很多次,都是根据自己对asp.net core认证过程的不断深入,删删减减。
整个asp.net core在StartUp类的Configure方法中使用一个UseAuthentication()的方式将认证这个中间件添加到了应用中。这个中间件的源码很短,如下:
注:认证中间件的整体流程是查找远程认证的IAuthenticationHandler,如果没有找到,则查找一个默认的handler,都是通过scheme来查找的,scheme这个东西出现的原因是它是IAthenticationHandler和相关Options的总称。
public class AuthenticationMiddleware { private readonly RequestDelegate _next; public AuthenticationMiddleware(RequestDelegate next, IAuthenticationSchemeProvider schemes) { if (next == null) throw new ArgumentNullException(nameof (next)); if (schemes == null) throw new ArgumentNullException(nameof (schemes)); this._next = next; this.Schemes = schemes; } public IAuthenticationSchemeProvider Schemes { get; set; } public async Task Invoke(HttpContext context) { context.Features.Set<IAuthenticationFeature>((IAuthenticationFeature) new AuthenticationFeature() { OriginalPath = context.Request.Path, OriginalPathBase = context.Request.PathBase }); IAuthenticationHandlerProvider handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>(); foreach (AuthenticationScheme authenticationScheme in await this.Schemes.GetRequestHandlerSchemesAsync())//GetReRequestHandlersAsync方法返回_requestHandlers字段保存的所有远程认证的Scheme { IAuthenticationRequestHandler handlerAsync = await handlers.GetHandlerAsync(context, authenticationScheme.Name) as IAuthenticationRequestHandler; bool flag = handlerAsync != null; if (flag) flag = await handlerAsync.HandleRequestAsync(); if (flag) return; } AuthenticationScheme authenticateSchemeAsync = await this.Schemes.GetDefaultAuthenticateSchemeAsync(); if (authenticateSchemeAsync != null) { AuthenticateResult authenticateResult = await context.AuthenticateAsync(authenticateSchemeAsync.Name); if (authenticateResult?.Principal != null) context.User = authenticateResult.Principal; } await this._next(context); } }
基本的流程是先找一个IAuthenticationRequestHandler,这个接口代表了远程认证,逻辑是①找到一个不为空的handler并执行HandlerRequestAsync;②如果执行结果为true,则返回,否则,继续下一个循环。如果没有找到任何IAuthenticationRequestHandler,则继续由GetDefaultAuthenticateSchemeAsync方法来找一个默认的本地认证Scheme,这个本地认证Scheme的逻辑是从AuthenticationOptions中先查看DefaultAuthenticationScheme是否有值(string),如果没有,再从DefaultScheme中查看是否有值(string)如果两者都没有,那么返回一个null。(注:认证中间件依赖一个IAuthenticationSchemeProvider(构造函数注入),后者的默认实现AuthenticationSchemeProvider依赖AuthenticationOptions类)。
整个asp.net core 认证的线索为IAuthenticationService,这个接口声明了5个动作方法,其中,具体的执行是由IAuthenticationHandler来执行的,这个接口定义了AuthenticateAsync()、ForbiddenAsync()和ChallengeAsync()。而SignInAsync和SignOutAsync则分别由IAuthenticationSignInHandler和IAuthenticationSignOutHandler来定义的。后两个接口也继承自IAuthenticationHandler,IAuthenticationHandler由IAuthenticationHandlerProvider来提供,IAuthenticationHandlerProvider使用IAuthenticationSchemeProvider来提供一个具体的AuthenticationScheme,AuthenticationScheme代表一个具体的方案,这个Scheme中包含了执行这个方案需要的HandlerType,也即是IAuthenticationHandler,从Scheme中拿到这个HandlerType之后,从DI或者ActivityUtils中得到具体的IAuthenticaitonHandler来执行最终逻辑。其他的诸如AuthenticateResult代表一个认证验证结果,他里面维护了一个AuthenticationTicket,还有一个AuthenticateProperties表示认证的一些特征,如颁发时间、过期时间等等。
这篇文章涉及的源码包括Microsoft.AspNETCore.Authentication.Abstraction、Microsoft.AspNETCore.Authentication.Core和Microsoft.AspNETCore.Authentication
认证和授权很相似,他们的英文也很相似,一个是Authentication认证,一个是Authorization授权。
asp.net core中的认证需要在Startup类中进行配置:
//ConfigureServices方法中: services.AddAuthentication(option => { option.DefaultScheme = "Cookie"; option.DefaultChallengeScheme = "Cookie"; option.DefaultAuthenticateScheme = "Cookie"; option.DefaultForbidScheme = "Cookie"; option.DefaultSignInScheme = "Cookie"; option.DefaultSignOutScheme = "Cookie"; }).AddCookie("Cookie", option => { option.LoginPath = "/Account/Login"; option.AccessDeniedPath = "/Account/Forbidden"; //....... });
//Configure方法中 app.UseAuthentication();
看一看到如果需要认证的话是需要分别在ConfigureService方法和Configure方法中分别进行配置的。
我们看到上面在AddAuthentication方法中配置了一个option,这个option是一个Action<AuthenticationOption>,在里面,写了一堆scheme。这个scheme是什么意思呢?我们先解释一下在asp.neet core中发生的这几个动作。在asp.net core中是有5个动作要发生的:
1、登陆(Signin):用户要进行登陆的动作。
2、登出(Signout):用户要进行登出。
3、Challenge:这个不好翻译,意思当用户需要请求一个被保护的资源时,系统要求用户进行登陆。总之他也是一个登陆的动作,但是被动的登陆,一般返回401。
4、Authenticate:认证,系统将用户的信息从token/cookie中读取出来。和登陆这个动作正好相反。
5、Forbid:系统对用户执行了拒绝的操作。一般返回403
上面这些动作最后都是由一个Handler来执行的,这个handler就是一个IAuthenticationHandler的实现。
我们先给出了上面的总结,再看一下具体的情况。asp.net core2.0开始上面的这些动作的执行都是通过HttpContext的扩展方法来执行的。我们拿登陆来说,其他都大同小异。
先看HttpContext.SigninAsync这个方法:
var claim = new Claim("name", "wallee");//claim相当于我的众多信息中的一个信息单元,还有年龄、性别、家庭等等 var identity = new ClaimsIdentity("身份证");//identity表示一个claim集合,这个集合代表了一个完整的“证件信息”,比如我的身份证 identity.AddClaim(claim);//将上面那个信息片段添加到我的身份证里面 var me=new ClaimsPrincipal(identity);//将身份证作为我个人的初始化参数,初始化一个ClaimsPrincipal就代表了我这个主体。还可以添加其他的identity,如还有驾驶证、准考证、会计证、计算机二级证等等
HttpContext.SignInAsync(me);//最后,利用这个主体,调用HttpContext的扩展方法进行登陆。
上面的代码中注释解释了一些和本文无关但又非常重要的信息,我们关键看最后哪一行:HttpContext.SigninAsync(principal);这行代码实现了最终的登陆。现在我们看一下它的实现:
public static Task SignInAsync(this HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties) { return context.RequestServices.GetRequiredService<IAuthenticationService>().SignInAsync(context, scheme, principal, properties); }
其实针对HttpContext的扩展方法都是调用IAuthenticationService来执行的,IAuthenticationService里面定义了针对上面描述的所有动作方法:
1 /// <summary>Used to provide authentication.</summary> 2 public interface IAuthenticationService 3 { 4 /// <summary>Authenticate for the specified authentication scheme.</summary> 5 /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Http.HttpContext" />.</param> 6 /// <param name="scheme">The name of the authentication scheme.</param> 7 /// <returns>The result.</returns> 8 Task<AuthenticateResult> AuthenticateAsync( 9 HttpContext context, 10 string scheme); 11 12 /// <summary>Challenge the specified authentication scheme.</summary> 13 /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Http.HttpContext" />.</param> 14 /// <param name="scheme">The name of the authentication scheme.</param> 15 /// <param name="properties">The <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationProperties" />.</param> 16 /// <returns>A task.</returns> 17 Task ChallengeAsync( 18 HttpContext context, 19 string scheme, 20 AuthenticationProperties properties); 21 22 /// <summary>Forbids the specified authentication scheme.</summary> 23 /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Http.HttpContext" />.</param> 24 /// <param name="scheme">The name of the authentication scheme.</param> 25 /// <param name="properties">The <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationProperties" />.</param> 26 /// <returns>A task.</returns> 27 Task ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties); 28 29 /// <summary> 30 /// Sign a principal in for the specified authentication scheme. 31 /// </summary> 32 /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Http.HttpContext" />.</param> 33 /// <param name="scheme">The name of the authentication scheme.</param> 34 /// <param name="principal">The <see cref="T:System.Security.Claims.ClaimsPrincipal" /> to sign in.</param> 35 /// <param name="properties">The <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationProperties" />.</param> 36 /// <returns>A task.</returns> 37 Task SignInAsync( 38 HttpContext context, 39 string scheme, 40 ClaimsPrincipal principal, 41 AuthenticationProperties properties); 42 43 /// <summary>Sign out the specified authentication scheme.</summary> 44 /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Http.HttpContext" />.</param> 45 /// <param name="scheme">The name of the authentication scheme.</param> 46 /// <param name="properties">The <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationProperties" />.</param> 47 /// <returns>A task.</returns> 48 Task SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties); 49 }
IAuthenticateService在services.AddAuthentication()方法中以scoped的生命周期被注入到了DI,表示针对每次请求的新的实例。同时还被注入的有另外几个比较关键的接口:
services.TryAddSingleton<IClaimsTransformation, NoopClaimsTransformation>();//ClaimsTransFormation用来在全局将ClaimsPrincipal添加一些新的Claims,默认注入的这个是啥都没干 services.TryAddScoped<IAuthenticationHandlerProvider, AuthenticationHandlerProvider>();//AuthenticationHandler的提供者,提供执行Authenticatoin、Forbidden和Challenge等动作的handler services.TryAddSingleton<IAuthenticationSchemeProvider, AuthenticationSchemeProvider>();//AuthenticationScheme的提供者,AuthenticationScheme是对AuthenticationHandler的描述,通过Scheme找到相应的Handler
IAuthenticationService是对IAuthenticationSchemeProvider和IAuthenticationHandlerProvider的封装,它有一个AuthenticationService的实现:
1 /// <summary> 2 /// Implements <see cref="T:Microsoft.AspNetCore.Authentication.IAuthenticationService" />. 3 /// </summary> 4 public class AuthenticationService : IAuthenticationService 5 { 6 /// <summary>Constructor.</summary> 7 /// <param name="schemes">The <see cref="T:Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider" />.</param> 8 /// <param name="handlers">The <see cref="T:Microsoft.AspNetCore.Authentication.IAuthenticationRequestHandler" />.</param> 9 /// <param name="transform">The <see cref="T:Microsoft.AspNetCore.Authentication.IClaimsTransformation" />.</param> 10 public AuthenticationService( 11 IAuthenticationSchemeProvider schemes, 12 IAuthenticationHandlerProvider handlers, 13 IClaimsTransformation transform) 14 { 15 this.Schemes = schemes; 16 this.Handlers = handlers; 17 this.Transform = transform; 18 } 19 20 /// <summary>Used to lookup AuthenticationSchemes.</summary> 21 public IAuthenticationSchemeProvider Schemes { get; } 22 23 /// <summary>Used to resolve IAuthenticationHandler instances.</summary> 24 public IAuthenticationHandlerProvider Handlers { get; } 25 26 /// <summary>Used for claims transformation.</summary> 27 public IClaimsTransformation Transform { get; } 28 29 /// <summary>Authenticate for the specified authentication scheme.</summary> 30 /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Http.HttpContext" />.</param> 31 /// <param name="scheme">The name of the authentication scheme.</param> 32 /// <returns>The result.</returns> 33 public virtual async Task<AuthenticateResult> AuthenticateAsync( 34 HttpContext context, 35 string scheme) 36 { 37 if (scheme == null) 38 { 39 scheme = (await this.Schemes.GetDefaultAuthenticateSchemeAsync())?.Name; 40 if (scheme == null) 41 throw new InvalidOperationException("No authenticationScheme was specified, and there was no DefaultAuthenticateScheme found."); 42 } 43 IAuthenticationHandler handlerAsync = await this.Handlers.GetHandlerAsync(context, scheme); 44 if (handlerAsync == null) 45 throw await this.CreateMissingHandlerException(scheme); 46 AuthenticateResult result = await handlerAsync.AuthenticateAsync(); 47 return result != null && result.Succeeded ? AuthenticateResult.Success(new AuthenticationTicket(await this.Transform.TransformAsync(result.Principal), result.Properties, result.Ticket.AuthenticationScheme)) : result; 48 } 49 50 /// <summary>Challenge the specified authentication scheme.</summary> 51 /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Http.HttpContext" />.</param> 52 /// <param name="scheme">The name of the authentication scheme.</param> 53 /// <param name="properties">The <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationProperties" />.</param> 54 /// <returns>A task.</returns> 55 public virtual async Task ChallengeAsync( 56 HttpContext context, 57 string scheme, 58 AuthenticationProperties properties) 59 { 60 if (scheme == null) 61 { 62 scheme = (await this.Schemes.GetDefaultChallengeSchemeAsync())?.Name; 63 if (scheme == null) 64 throw new InvalidOperationException("No authenticationScheme was specified, and there was no DefaultChallengeScheme found."); 65 } 66 IAuthenticationHandler handlerAsync = await this.Handlers.GetHandlerAsync(context, scheme); 67 if (handlerAsync == null) 68 throw await this.CreateMissingHandlerException(scheme); 69 await handlerAsync.ChallengeAsync(properties); 70 } 71 72 /// <summary>Forbid the specified authentication scheme.</summary> 73 /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Http.HttpContext" />.</param> 74 /// <param name="scheme">The name of the authentication scheme.</param> 75 /// <param name="properties">The <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationProperties" />.</param> 76 /// <returns>A task.</returns> 77 public virtual async Task ForbidAsync( 78 HttpContext context, 79 string scheme, 80 AuthenticationProperties properties) 81 { 82 if (scheme == null) 83 { 84 scheme = (await this.Schemes.GetDefaultForbidSchemeAsync())?.Name; 85 if (scheme == null) 86 throw new InvalidOperationException("No authenticationScheme was specified, and there was no DefaultForbidScheme found."); 87 } 88 IAuthenticationHandler handlerAsync = await this.Handlers.GetHandlerAsync(context, scheme); 89 if (handlerAsync == null) 90 throw await this.CreateMissingHandlerException(scheme); 91 await handlerAsync.ForbidAsync(properties); 92 } 93 94 /// <summary> 95 /// Sign a principal in for the specified authentication scheme. 96 /// </summary> 97 /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Http.HttpContext" />.</param> 98 /// <param name="scheme">The name of the authentication scheme.</param> 99 /// <param name="principal">The <see cref="T:System.Security.Claims.ClaimsPrincipal" /> to sign in.</param> 100 /// <param name="properties">The <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationProperties" />.</param> 101 /// <returns>A task.</returns> 102 public virtual async Task SignInAsync( 103 HttpContext context, 104 string scheme, 105 ClaimsPrincipal principal, 106 AuthenticationProperties properties) 107 { 108 if (principal == null) 109 throw new ArgumentNullException(nameof (principal)); 110 if (scheme == null) 111 { 112 scheme = (await this.Schemes.GetDefaultSignInSchemeAsync())?.Name; 113 if (scheme == null) 114 throw new InvalidOperationException("No authenticationScheme was specified, and there was no DefaultSignInScheme found."); 115 } 116 IAuthenticationHandler handlerAsync = await this.Handlers.GetHandlerAsync(context, scheme); 117 if (handlerAsync == null) 118 throw await this.CreateMissingSignInHandlerException(scheme); 119 if (!(handlerAsync is IAuthenticationSignInHandler authenticationSignInHandler)) 120 throw await this.CreateMismatchedSignInHandlerException(scheme, handlerAsync); 121 await authenticationSignInHandler.SignInAsync(principal, properties); 122 } 123 124 /// <summary>Sign out the specified authentication scheme.</summary> 125 /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Http.HttpContext" />.</param> 126 /// <param name="scheme">The name of the authentication scheme.</param> 127 /// <param name="properties">The <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationProperties" />.</param> 128 /// <returns>A task.</returns> 129 public virtual async Task SignOutAsync( 130 HttpContext context, 131 string scheme, 132 AuthenticationProperties properties) 133 { 134 if (scheme == null) 135 { 136 scheme = (await this.Schemes.GetDefaultSignOutSchemeAsync())?.Name; 137 if (scheme == null) 138 throw new InvalidOperationException("No authenticationScheme was specified, and there was no DefaultSignOutScheme found."); 139 } 140 IAuthenticationHandler handlerAsync = await this.Handlers.GetHandlerAsync(context, scheme); 141 if (handlerAsync == null) 142 throw await this.CreateMissingSignOutHandlerException(scheme); 143 if (!(handlerAsync is IAuthenticationSignOutHandler authenticationSignOutHandler)) 144 throw await this.CreateMismatchedSignOutHandlerException(scheme, handlerAsync); 145 await authenticationSignOutHandler.SignOutAsync(properties); 146 } 147 148 private async Task<Exception> CreateMissingHandlerException(string scheme) 149 { 150 string str1 = string.Join(", ", (await this.Schemes.GetAllSchemesAsync()).Select<AuthenticationScheme, string>((Func<AuthenticationScheme, string>) (sch => sch.Name))); 151 string str2 = string.Format(" Did you forget to call AddAuthentication().Add[SomeAuthHandler](\"{0}\",...)?", (object) scheme); 152 return !string.IsNullOrEmpty(str1) ? (Exception) new InvalidOperationException(string.Format("No authentication handler is registered for the scheme '{0}'. The registered schemes are: {1}.", (object) scheme, (object) str1) + str2) : (Exception) new InvalidOperationException("No authentication handlers are registered." + str2); 153 } 154 155 private async Task<string> GetAllSignInSchemeNames() 156 { 157 return string.Join(", ", (await this.Schemes.GetAllSchemesAsync()).Where<AuthenticationScheme>((Func<AuthenticationScheme, bool>) (sch => typeof (IAuthenticationSignInHandler).IsAssignableFrom(sch.HandlerType))).Select<AuthenticationScheme, string>((Func<AuthenticationScheme, string>) (sch => sch.Name))); 158 } 159 160 private async Task<Exception> CreateMissingSignInHandlerException(string scheme) 161 { 162 string signInSchemeNames = await this.GetAllSignInSchemeNames(); 163 string str = string.Format(" Did you forget to call AddAuthentication().AddCookies(\"{0}\",...)?", (object) scheme); 164 return !string.IsNullOrEmpty(signInSchemeNames) ? (Exception) new InvalidOperationException(string.Format("No sign-in authentication handler is registered for the scheme '{0}'. The registered sign-in schemes are: {1}.", (object) scheme, (object) signInSchemeNames) + str) : (Exception) new InvalidOperationException("No sign-in authentication handlers are registered." + str); 165 } 166 167 private async Task<Exception> CreateMismatchedSignInHandlerException( 168 string scheme, 169 IAuthenticationHandler handler) 170 { 171 string signInSchemeNames = await this.GetAllSignInSchemeNames(); 172 string str = string.Format("The authentication handler registered for scheme '{0}' is '{1}' which cannot be used for SignInAsync. ", (object) scheme, (object) handler.GetType().Name); 173 return !string.IsNullOrEmpty(signInSchemeNames) ? (Exception) new InvalidOperationException(str + string.Format("The registered sign-in schemes are: {0}.", (object) signInSchemeNames)) : (Exception) new InvalidOperationException(str + "Did you forget to call AddAuthentication().AddCookies(\"Cookies\") and SignInAsync(\"Cookies\",...)?"); 174 } 175 176 private async Task<string> GetAllSignOutSchemeNames() 177 { 178 return string.Join(", ", (await this.Schemes.GetAllSchemesAsync()).Where<AuthenticationScheme>((Func<AuthenticationScheme, bool>) (sch => typeof (IAuthenticationSignOutHandler).IsAssignableFrom(sch.HandlerType))).Select<AuthenticationScheme, string>((Func<AuthenticationScheme, string>) (sch => sch.Name))); 179 } 180 181 private async Task<Exception> CreateMissingSignOutHandlerException(string scheme) 182 { 183 string signOutSchemeNames = await this.GetAllSignOutSchemeNames(); 184 string str = string.Format(" Did you forget to call AddAuthentication().AddCookies(\"{0}\",...)?", (object) scheme); 185 return !string.IsNullOrEmpty(signOutSchemeNames) ? (Exception) new InvalidOperationException(string.Format("No sign-out authentication handler is registered for the scheme '{0}'. The registered sign-out schemes are: {1}.", (object) scheme, (object) signOutSchemeNames) + str) : (Exception) new InvalidOperationException("No sign-out authentication handlers are registered." + str); 186 } 187 188 private async Task<Exception> CreateMismatchedSignOutHandlerException( 189 string scheme, 190 IAuthenticationHandler handler) 191 { 192 string signOutSchemeNames = await this.GetAllSignOutSchemeNames(); 193 string str = string.Format("The authentication handler registered for scheme '{0}' is '{1}' which cannot be used for {2}. ", (object) scheme, (object) handler.GetType().Name, (object) "SignOutAsync"); 194 return !string.IsNullOrEmpty(signOutSchemeNames) ? (Exception) new InvalidOperationException(str + string.Format("The registered sign-out schemes are: {0}.", (object) signOutSchemeNames)) : (Exception) new InvalidOperationException(str + string.Format("Did you forget to call AddAuthentication().AddCookies(\"Cookies\") and {0}(\"Cookies\",...)?", (object) "SignOutAsync")); 195 } 196 }
这个基本就是asp.net core 认证的整体概况了,先看一下整体的逻辑,在下一部分,我们再把一些相关的类型做一些补充说明。
可以看到AuthenticationService里面定义的这些AuthenticationAsync、ForbiddenAsync等等动作方法基本都遵循了一个逻辑:
①首先判断传入的scheme是否为null,如果为null,那么根据IAuthenticationSchemeProvider类型的Schemes属性来找出一个默认的scheme,如果上述两个都失败,则抛出异常。
②第一步成功的前提下,利用IAuthenticationHandlerProvider类型的Handlers属性根据找出的scheme来生成一个handler。
③在AuthenticationAsync、ForbiddenAsync和ChallengeAsync方法中,直接调用生成的handler的同名方法来执行最终的逻辑,而在SignInAsync和SignOutAsync中要判断拿到的这个Handler是否分别实现了IAuthenticationSignInHandler和IAuthenticationSignOutHandler这两个接口,如果没有实现,则爆出异常。
至于SignIn和SignOut这两个接口从IAuthenticatoinHandler中剥离出去是因为IAuthenticationHandler只是实现了对用户凭证的验证,至于SignIn和SignOut,现在大多数应用使用的登录方式都有所不同,况且这两个功能实现的是凭证的获取/发放,放在IAuthenticationHandler不合适。
public interface IAuthenticationSignInHandler : IAuthenticationSignOutHandler, IAuthenticationHandler { /// <summary>Handle sign in.</summary> /// <param name="user">The <see cref="T:System.Security.Claims.ClaimsPrincipal" /> user.</param> /// <param name="properties">The <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationProperties" /> that contains the extra meta-data arriving with the authentication.</param> /// <returns>A task.</returns> Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties); }
public interface IAuthenticationSignOutHandler : IAuthenticationHandler { /// <summary>Signout behavior.</summary> /// <param name="properties">The <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationProperties" /> that contains the extra meta-data arriving with the authentication.</param> /// <returns>A task.</returns> Task SignOutAsync(AuthenticationProperties properties); }
关键类型
AuthenticationScheme
1 public class AuthenticationScheme 2 { 3 /// <summary>Constructor.</summary> 4 /// <param name="name">The name for the authentication scheme.</param> 5 /// <param name="displayName">The display name for the authentication scheme.</param> 6 /// <param name="handlerType">The <see cref="T:Microsoft.AspNetCore.Authentication.IAuthenticationHandler" /> type that handles this scheme.</param> 7 public AuthenticationScheme(string name, string displayName, Type handlerType) 8 { 9 if (name == null) 10 throw new ArgumentNullException(nameof (name)); 11 if (handlerType == (Type) null) 12 throw new ArgumentNullException(nameof (handlerType)); 13 if (!typeof (IAuthenticationHandler).IsAssignableFrom(handlerType)) 14 throw new ArgumentException("handlerType must implement IAuthenticationHandler."); 15 this.Name = name; 16 this.HandlerType = handlerType; 17 this.DisplayName = displayName; 18 } 19 20 /// <summary>The name of the authentication scheme.</summary> 21 public string Name { get; } 22 23 /// <summary> 24 /// The display name for the scheme. Null is valid and used for non user facing schemes. 25 /// </summary> 26 public string DisplayName { get; } 27 28 /// <summary> 29 /// The <see cref="T:Microsoft.AspNetCore.Authentication.IAuthenticationHandler" /> type that handles this scheme. 30 /// </summary> 31 public Type HandlerType { get; } 32 }
一个AuthenticationScheme就是一个对IAuthenticationHandler的描述,它为一个特定的handlerType分配了一个名称(name)。它的构造函数接收三个参数了分别初始化了内部的三个属性,并对这三个参数做了严格的校验保证输入的参数有效。
AuthenticationSchemeBuilder
1 public class AuthenticationSchemeBuilder 2 { 3 /// <summary>Constructor.</summary> 4 /// <param name="name">The name of the scheme being built.</param> 5 public AuthenticationSchemeBuilder(string name) 6 { 7 this.Name = name; 8 } 9 10 /// <summary>The name of the scheme being built.</summary> 11 public string Name { get; } 12 13 /// <summary>The display name for the scheme being built.</summary> 14 public string DisplayName { get; set; } 15 16 /// <summary> 17 /// The <see cref="T:Microsoft.AspNetCore.Authentication.IAuthenticationHandler" /> type responsible for this scheme. 18 /// </summary> 19 public Type HandlerType { get; set; } 20 21 /// <summary> 22 /// Builds the <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationScheme" /> instance. 23 /// </summary> 24 /// <returns></returns> 25 public AuthenticationScheme Build() 26 { 27 return new AuthenticationScheme(this.Name, this.DisplayName, this.HandlerType); 28 } 29 }
从名字就能看出来它是AuthenticationScheme的建造者,它内部包含的三个属性和AuthenticationScheme是一样的。它的构造函数需要一个string类型的name参数来初始化name,没有对输入的参数做任何校验,另外毫无意外的它有一个Build方法,用自身的这三个属性来new一个AuthenticationScheme。
AutenticaitonOptions
1 public class AuthenticationOptions 2 { 3 private readonly IList<AuthenticationSchemeBuilder> _schemes = (IList<AuthenticationSchemeBuilder>) new List<AuthenticationSchemeBuilder>(); 4 5 /// <summary> 6 /// Returns the schemes in the order they were added (important for request handling priority) 7 /// </summary> 8 public IEnumerable<AuthenticationSchemeBuilder> Schemes 9 { 10 get 11 { 12 return (IEnumerable<AuthenticationSchemeBuilder>) this._schemes; 13 } 14 } 15 16 /// <summary>Maps schemes by name.</summary> 17 public IDictionary<string, AuthenticationSchemeBuilder> SchemeMap { get; } = (IDictionary<string, AuthenticationSchemeBuilder>) new Dictionary<string, AuthenticationSchemeBuilder>((IEqualityComparer<string>) StringComparer.Ordinal); 18 19 /// <summary> 20 /// Adds an <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationScheme" />. 21 /// </summary> 22 /// <param name="name">The name of the scheme being added.</param> 23 /// <param name="configureBuilder">Configures the scheme.</param> 24 public void AddScheme( 25 string name, 26 Action<AuthenticationSchemeBuilder> configureBuilder) 27 { 28 if (name == null) 29 throw new ArgumentNullException(nameof (name)); 30 if (configureBuilder == null) 31 throw new ArgumentNullException(nameof (configureBuilder)); 32 if (this.SchemeMap.ContainsKey(name)) 33 throw new InvalidOperationException("Scheme already exists: " + name); 34 AuthenticationSchemeBuilder authenticationSchemeBuilder = new AuthenticationSchemeBuilder(name); 35 configureBuilder(authenticationSchemeBuilder); 36 this._schemes.Add(authenticationSchemeBuilder); 37 this.SchemeMap[name] = authenticationSchemeBuilder; 38 } 39 40 /// <summary> 41 /// Adds an <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationScheme" />. 42 /// </summary> 43 /// <typeparam name="THandler">The <see cref="T:Microsoft.AspNetCore.Authentication.IAuthenticationHandler" /> responsible for the scheme.</typeparam> 44 /// <param name="name">The name of the scheme being added.</param> 45 /// <param name="displayName">The display name for the scheme.</param> 46 public void AddScheme<THandler>(string name, string displayName) where THandler : IAuthenticationHandler 47 { 48 this.AddScheme(name, (Action<AuthenticationSchemeBuilder>) (b => 49 { 50 b.DisplayName = displayName; 51 b.HandlerType = typeof (THandler); 52 })); 53 } 54 55 /// <summary> 56 /// Used as the fallback default scheme for all the other defaults. 57 /// </summary> 58 public string DefaultScheme { get; set; } 59 60 /// <summary> 61 /// Used as the default scheme by <see cref="M:Microsoft.AspNetCore.Authentication.IAuthenticationService.AuthenticateAsync(Microsoft.AspNetCore.Http.HttpContext,System.String)" />. 62 /// </summary> 63 public string DefaultAuthenticateScheme { get; set; } 64 65 /// <summary> 66 /// Used as the default scheme by <see cref="M:Microsoft.AspNetCore.Authentication.IAuthenticationService.SignInAsync(Microsoft.AspNetCore.Http.HttpContext,System.String,System.Security.Claims.ClaimsPrincipal,Microsoft.AspNetCore.Authentication.AuthenticationProperties)" />. 67 /// </summary> 68 public string DefaultSignInScheme { get; set; } 69 70 /// <summary> 71 /// Used as the default scheme by <see cref="M:Microsoft.AspNetCore.Authentication.IAuthenticationService.SignOutAsync(Microsoft.AspNetCore.Http.HttpContext,System.String,Microsoft.AspNetCore.Authentication.AuthenticationProperties)" />. 72 /// </summary> 73 public string DefaultSignOutScheme { get; set; } 74 75 /// <summary> 76 /// Used as the default scheme by <see cref="M:Microsoft.AspNetCore.Authentication.IAuthenticationService.ChallengeAsync(Microsoft.AspNetCore.Http.HttpContext,System.String,Microsoft.AspNetCore.Authentication.AuthenticationProperties)" />. 77 /// </summary> 78 public string DefaultChallengeScheme { get; set; } 79 80 /// <summary> 81 /// Used as the default scheme by <see cref="M:Microsoft.AspNetCore.Authentication.IAuthenticationService.ForbidAsync(Microsoft.AspNetCore.Http.HttpContext,System.String,Microsoft.AspNetCore.Authentication.AuthenticationProperties)" />. 82 /// </summary> 83 public string DefaultForbidScheme { get; set; } 84 }
这个类为添加Scheme提供了便利,它维护了一个AuthenticationSchemeBuilder的列表和一个同类型的字典。------------------------
IAuthenticationHandlerProvider
public interface IAuthenticationHandlerProvider { Task<IAuthenticationHandler> GetHandlerAsync(HttpContext context, string authenticationScheme); }
IAuthenticationHandler负责对用户的凭证进行校验,而这个Provider就是用来提供一个IAuthenticationHandler,它只有一个方法就是GetHandlerAsync(HttpContext context,string authenticationScheme)。从方法的参数传入也能知道IAuthenticationHnadlerProvider的实现依赖于AuthenticationScheme,确实,它的实现AuthenticationHandlerProvider里面确实维护了一个IAuthenticationSchemeProvider:
1 public class AuthenticationHandlerProvider : IAuthenticationHandlerProvider 2 { 3 private Dictionary<string, IAuthenticationHandler> _handlerMap = new Dictionary<string, IAuthenticationHandler>((IEqualityComparer<string>) StringComparer.Ordinal); 4 5 /// <summary>Constructor.</summary> 6 /// <param name="schemes">The <see cref="T:Microsoft.AspNetCore.Authentication.IAuthenticationHandlerProvider" />.</param> 7 public AuthenticationHandlerProvider(IAuthenticationSchemeProvider schemes) 8 { 9 this.Schemes = schemes; 10 } 11 12 /// <summary> 13 /// The <see cref="T:Microsoft.AspNetCore.Authentication.IAuthenticationHandlerProvider" />. 14 /// </summary> 15 public IAuthenticationSchemeProvider Schemes { get; } 16 17 /// <summary>Returns the handler instance that will be used.</summary> 18 /// <param name="context">The context.</param> 19 /// <param name="authenticationScheme">The name of the authentication scheme being handled.</param> 20 /// <returns>The handler instance.</returns> 21 public async Task<IAuthenticationHandler> GetHandlerAsync( 22 HttpContext context, 23 string authenticationScheme) 24 { 25 if (this._handlerMap.ContainsKey(authenticationScheme)) 26 return this._handlerMap[authenticationScheme]; 27 AuthenticationScheme schemeAsync = await this.Schemes.GetSchemeAsync(authenticationScheme); 28 if (schemeAsync == null) 29 return (IAuthenticationHandler) null; 30 if ((context.RequestServices.GetService(schemeAsync.HandlerType) ?? ActivatorUtilities.CreateInstance(context.RequestServices, schemeAsync.HandlerType)) is IAuthenticationHandler handler) 31 { 32 await handler.InitializeAsync(schemeAsync, context); 33 this._handlerMap[authenticationScheme] = handler; 34 } 35 return handler; 36 } 37 }
IAuthenticationHandlerProvider的目的很明确,就是要提供一个IAuthenticationHandler,它的逻辑如下:
①首先根据authenticationScheme查看_handlerMap是否包含相应的handler如果包含直接返回这个handler。
②如果没有从第一步中找到,那么就从Schemes属性中根据authenticationScheme找出相应的AuthenticationScheme,如果这个Scheme为空,那么直接返回一个null。
③如果从Schemes属性中找出的AuthenticationScheme不为空,那么或者从传入的HttpContext类型的context.RequestServices.GetService方法中找Handler,或者使用ActivatorUtilities来创建一个,不管使用那种方式都是从拿到的scheme中记录的handlerType来获取handler的。如果是一个IAuthenticationHandler,那么调用handler. InitializeAsync方法(注一)来初始化本身,并将这个handler放入自身的_handlerMap字典中。最后将这个handler返回。
AuthenticateResult
1 public class AuthenticateResult 2 { 3 protected AuthenticateResult() 4 { 5 } 6 7 /// <summary> 8 /// If a ticket was produced, authenticate was successful. 9 /// </summary> 10 public bool Succeeded 11 { 12 get 13 { 14 return this.Ticket != null; 15 } 16 } 17 18 /// <summary>The authentication ticket.</summary> 19 public AuthenticationTicket Ticket { get; protected set; } 20 21 /// <summary> 22 /// Gets the claims-principal with authenticated user identities. 23 /// </summary> 24 public ClaimsPrincipal Principal 25 { 26 get 27 { 28 return this.Ticket?.Principal; 29 } 30 } 31 32 /// <summary> 33 /// Additional state values for the authentication session. 34 /// </summary> 35 public AuthenticationProperties Properties { get; protected set; } 36 37 /// <summary>Holds failure information from the authentication.</summary> 38 public Exception Failure { get; protected set; } 39 40 /// <summary> 41 /// Indicates that there was no information returned for this authentication scheme. 42 /// </summary> 43 public bool None { get; protected set; } 44 45 /// <summary>Indicates that authentication was successful.</summary> 46 /// <param name="ticket">The ticket representing the authentication result.</param> 47 /// <returns>The result.</returns> 48 public static AuthenticateResult Success(AuthenticationTicket ticket) 49 { 50 if (ticket == null) 51 throw new ArgumentNullException(nameof (ticket)); 52 return new AuthenticateResult() 53 { 54 Ticket = ticket, 55 Properties = ticket.Properties 56 }; 57 } 58 59 /// <summary> 60 /// Indicates that there was no information returned for this authentication scheme. 61 /// </summary> 62 /// <returns>The result.</returns> 63 public static AuthenticateResult NoResult() 64 { 65 return new AuthenticateResult() { None = true }; 66 } 67 68 /// <summary> 69 /// Indicates that there was a failure during authentication. 70 /// </summary> 71 /// <param name="failure">The failure exception.</param> 72 /// <returns>The result.</returns> 73 public static AuthenticateResult Fail(Exception failure) 74 { 75 return new AuthenticateResult() { Failure = failure }; 76 } 77 78 /// <summary> 79 /// Indicates that there was a failure during authentication. 80 /// </summary> 81 /// <param name="failure">The failure exception.</param> 82 /// <param name="properties">Additional state values for the authentication session.</param> 83 /// <returns>The result.</returns> 84 public static AuthenticateResult Fail( 85 Exception failure, 86 AuthenticationProperties properties) 87 { 88 return new AuthenticateResult() 89 { 90 Failure = failure, 91 Properties = properties 92 }; 93 } 94 95 /// <summary> 96 /// Indicates that there was a failure during authentication. 97 /// </summary> 98 /// <param name="failureMessage">The failure message.</param> 99 /// <returns>The result.</returns> 100 public static AuthenticateResult Fail(string failureMessage) 101 { 102 return AuthenticateResult.Fail(new Exception(failureMessage)); 103 } 104 105 /// <summary> 106 /// Indicates that there was a failure during authentication. 107 /// </summary> 108 /// <param name="failureMessage">The failure message.</param> 109 /// <param name="properties">Additional state values for the authentication session.</param> 110 /// <returns>The result.</returns> 111 public static AuthenticateResult Fail( 112 string failureMessage, 113 AuthenticationProperties properties) 114 { 115 return AuthenticateResult.Fail(new Exception(failureMessage), properties); 116 } 117 }
一个认证结果,表示AuthenticationService中的方法返回的结果。典型的状态模式。它内部维护一个AuthenticationTicket。可直接调用Success方法或这Fail方法来返回包含相应状态的Result。
AuthenticatoinTicket
1 public class AuthenticationTicket 2 { 3 /// <summary> 4 /// Initializes a new instance of the <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationTicket" /> class 5 /// </summary> 6 /// <param name="principal">the <see cref="T:System.Security.Claims.ClaimsPrincipal" /> that represents the authenticated user.</param> 7 /// <param name="properties">additional properties that can be consumed by the user or runtime.</param> 8 /// <param name="authenticationScheme">the authentication middleware that was responsible for this ticket.</param> 9 public AuthenticationTicket( 10 ClaimsPrincipal principal, 11 AuthenticationProperties properties, 12 string authenticationScheme) 13 { 14 if (principal == null) 15 throw new ArgumentNullException(nameof (principal)); 16 this.AuthenticationScheme = authenticationScheme; 17 this.Principal = principal; 18 this.Properties = properties ?? new AuthenticationProperties(); 19 } 20 21 /// <summary> 22 /// Initializes a new instance of the <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationTicket" /> class 23 /// </summary> 24 /// <param name="principal">the <see cref="T:System.Security.Claims.ClaimsPrincipal" /> that represents the authenticated user.</param> 25 /// <param name="authenticationScheme">the authentication middleware that was responsible for this ticket.</param> 26 public AuthenticationTicket(ClaimsPrincipal principal, string authenticationScheme) 27 : this(principal, (AuthenticationProperties) null, authenticationScheme) 28 { 29 } 30 31 /// <summary>Gets the authentication type.</summary> 32 public string AuthenticationScheme { get; private set; } 33 34 /// <summary> 35 /// Gets the claims-principal with authenticated user identities. 36 /// </summary> 37 public ClaimsPrincipal Principal { get; private set; } 38 39 /// <summary> 40 /// Additional state values for the authentication session. 41 /// </summary> 42 public AuthenticationProperties Properties { get; private set; } 43 }
表示一个经过认证后颁发的证书,里面包含ClaimsPrincipal、AuthenticationScheme和AuthenticationProperties三个属性,ClaimsPrincipal表示证书的主体,如姓名、电话等等信息,AuthenticationProperties表示证书的相关信息,如颁发时间、过期时间和重定向地址等等。
AuthenticationProperties
1 public class AuthenticationProperties 2 { 3 internal const string IssuedUtcKey = ".issued"; 4 internal const string ExpiresUtcKey = ".expires"; 5 internal const string IsPersistentKey = ".persistent"; 6 internal const string RedirectUriKey = ".redirect"; 7 internal const string RefreshKey = ".refresh"; 8 internal const string UtcDateTimeFormat = "r"; 9 10 /// <summary> 11 /// Initializes a new instance of the <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationProperties" /> class. 12 /// </summary> 13 public AuthenticationProperties() 14 : this((IDictionary<string, string>) null, (IDictionary<string, object>) null) 15 { 16 } 17 18 /// <summary> 19 /// Initializes a new instance of the <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationProperties" /> class. 20 /// </summary> 21 /// <param name="items">State values dictionary to use.</param> 22 public AuthenticationProperties(IDictionary<string, string> items) 23 : this(items, (IDictionary<string, object>) null) 24 { 25 } 26 27 /// <summary> 28 /// Initializes a new instance of the <see cref="T:Microsoft.AspNetCore.Authentication.AuthenticationProperties" /> class. 29 /// </summary> 30 /// <param name="items">State values dictionary to use.</param> 31 /// <param name="parameters">Parameters dictionary to use.</param> 32 public AuthenticationProperties( 33 IDictionary<string, string> items, 34 IDictionary<string, object> parameters) 35 { 36 this.Items = items ?? (IDictionary<string, string>) new Dictionary<string, string>((IEqualityComparer<string>) StringComparer.Ordinal); 37 this.Parameters = parameters ?? (IDictionary<string, object>) new Dictionary<string, object>((IEqualityComparer<string>) StringComparer.Ordinal); 38 } 39 40 /// <summary>State values about the authentication session.</summary> 41 public IDictionary<string, string> Items { get; } 42 43 /// <summary> 44 /// Collection of parameters that are passed to the authentication handler. These are not intended for 45 /// serialization or persistence, only for flowing data between call sites. 46 /// </summary> 47 public IDictionary<string, object> Parameters { get; } 48 49 /// <summary> 50 /// Gets or sets whether the authentication session is persisted across multiple requests. 51 /// </summary> 52 public bool IsPersistent 53 { 54 get 55 { 56 return this.GetString(".persistent") != null; 57 } 58 set 59 { 60 this.SetString(".persistent", value ? string.Empty : (string) null); 61 } 62 } 63 64 /// <summary> 65 /// Gets or sets the full path or absolute URI to be used as an http redirect response value. 66 /// </summary> 67 public string RedirectUri 68 { 69 get 70 { 71 return this.GetString(".redirect"); 72 } 73 set 74 { 75 this.SetString(".redirect", value); 76 } 77 } 78 79 /// <summary> 80 /// Gets or sets the time at which the authentication ticket was issued. 81 /// </summary> 82 public DateTimeOffset? IssuedUtc 83 { 84 get 85 { 86 return this.GetDateTimeOffset(".issued"); 87 } 88 set 89 { 90 this.SetDateTimeOffset(".issued", value); 91 } 92 } 93 94 /// <summary> 95 /// Gets or sets the time at which the authentication ticket expires. 96 /// </summary> 97 public DateTimeOffset? ExpiresUtc 98 { 99 get 100 { 101 return this.GetDateTimeOffset(".expires"); 102 } 103 set 104 { 105 this.SetDateTimeOffset(".expires", value); 106 } 107 } 108 109 /// <summary> 110 /// Gets or sets if refreshing the authentication session should be allowed. 111 /// </summary> 112 public bool? AllowRefresh 113 { 114 get 115 { 116 return this.GetBool(".refresh"); 117 } 118 set 119 { 120 this.SetBool(".refresh", value); 121 } 122 } 123 124 /// <summary> 125 /// Get a string value from the <see cref="P:Microsoft.AspNetCore.Authentication.AuthenticationProperties.Items" /> collection. 126 /// </summary> 127 /// <param name="key">Property key.</param> 128 /// <returns>Retrieved value or <c>null</c> if the property is not set.</returns> 129 public string GetString(string key) 130 { 131 string str; 132 return !this.Items.TryGetValue(key, out str) ? (string) null : str; 133 } 134 135 /// <summary> 136 /// Set a string value in the <see cref="P:Microsoft.AspNetCore.Authentication.AuthenticationProperties.Items" /> collection. 137 /// </summary> 138 /// <param name="key">Property key.</param> 139 /// <param name="value">Value to set or <c>null</c> to remove the property.</param> 140 public void SetString(string key, string value) 141 { 142 if (value != null) 143 { 144 this.Items[key] = value; 145 } 146 else 147 { 148 if (!this.Items.ContainsKey(key)) 149 return; 150 this.Items.Remove(key); 151 } 152 } 153 154 /// <summary> 155 /// Get a parameter from the <see cref="P:Microsoft.AspNetCore.Authentication.AuthenticationProperties.Parameters" /> collection. 156 /// </summary> 157 /// <typeparam name="T">Parameter type.</typeparam> 158 /// <param name="key">Parameter key.</param> 159 /// <returns>Retrieved value or the default value if the property is not set.</returns> 160 public T GetParameter<T>(string key) 161 { 162 object obj1; 163 return this.Parameters.TryGetValue(key, out obj1) && obj1 is T obj2 ? obj2 : default (T); 164 } 165 166 /// <summary> 167 /// Set a parameter value in the <see cref="P:Microsoft.AspNetCore.Authentication.AuthenticationProperties.Parameters" /> collection. 168 /// </summary> 169 /// <typeparam name="T">Parameter type.</typeparam> 170 /// <param name="key">Parameter key.</param> 171 /// <param name="value">Value to set.</param> 172 public void SetParameter<T>(string key, T value) 173 { 174 this.Parameters[key] = (object) value; 175 } 176 177 /// <summary> 178 /// Get a bool value from the <see cref="P:Microsoft.AspNetCore.Authentication.AuthenticationProperties.Items" /> collection. 179 /// </summary> 180 /// <param name="key">Property key.</param> 181 /// <returns>Retrieved value or <c>null</c> if the property is not set.</returns> 182 protected bool? GetBool(string key) 183 { 184 string str; 185 bool result; 186 return this.Items.TryGetValue(key, out str) && bool.TryParse(str, out result) ? new bool?(result) : new bool?(); 187 } 188 189 /// <summary> 190 /// Set a bool value in the <see cref="P:Microsoft.AspNetCore.Authentication.AuthenticationProperties.Items" /> collection. 191 /// </summary> 192 /// <param name="key">Property key.</param> 193 /// <param name="value">Value to set or <c>null</c> to remove the property.</param> 194 protected void SetBool(string key, bool? value) 195 { 196 if (value.HasValue) 197 { 198 this.Items[key] = value.Value.ToString(); 199 } 200 else 201 { 202 if (!this.Items.ContainsKey(key)) 203 return; 204 this.Items.Remove(key); 205 } 206 } 207 208 /// <summary> 209 /// Get a DateTimeOffset value from the <see cref="P:Microsoft.AspNetCore.Authentication.AuthenticationProperties.Items" /> collection. 210 /// </summary> 211 /// <param name="key">Property key.</param> 212 /// <returns>Retrieved value or <c>null</c> if the property is not set.</returns> 213 protected DateTimeOffset? GetDateTimeOffset(string key) 214 { 215 string input; 216 DateTimeOffset result; 217 return this.Items.TryGetValue(key, out input) && DateTimeOffset.TryParseExact(input, "r", (IFormatProvider) CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out result) ? new DateTimeOffset?(result) : new DateTimeOffset?(); 218 } 219 220 /// <summary> 221 /// Set a DateTimeOffset value in the <see cref="P:Microsoft.AspNetCore.Authentication.AuthenticationProperties.Items" /> collection. 222 /// </summary> 223 /// <param name="key">Property key.</param> 224 /// <param name="value">Value to set or <c>null</c> to remove the property.</param> 225 protected void SetDateTimeOffset(string key, DateTimeOffset? value) 226 { 227 if (value.HasValue) 228 { 229 this.Items[key] = value.Value.ToString("r", (IFormatProvider) CultureInfo.InvariantCulture); 230 } 231 else 232 { 233 if (!this.Items.ContainsKey(key)) 234 return; 235 this.Items.Remove(key); 236 } 237 } 238 }
IClaimsTransformation
1 public interface IClaimsTransformation 2 { 3 /// <summary> 4 /// Provides a central transformation point to change the specified principal. 5 /// Note: this will be run on each AuthenticateAsync call, so its safer to 6 /// return a new ClaimsPrincipal if your transformation is not idempotent. 7 /// </summary> 8 /// <param name="principal">The <see cref="T:System.Security.Claims.ClaimsPrincipal" /> to transform.</param> 9 /// <returns>The transformed principal.</returns> 10 Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal); 11 }
这个接口可以为传入的principal提供转换,适合全局为principal添加一些额外的claim。