整體概況
整個asp.net core在StartUp類的Configure方法中使用一個UseAuthentication()的方式將認證這個中間件添加到了應用中。這個中間件的源碼很短,如下:
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。