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   }
View Code

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   }
View Code

这个基本就是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   }
View Code

一个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   }
View Code

从名字就能看出来它是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   }
View Code

这个类为添加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   }
View Code

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   }
View Code

一个认证结果,表示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   }
View Code

表示一个经过认证后颁发的证书,里面包含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   }
View Code

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   }
View Code

这个接口可以为传入的principal提供转换,适合全局为principal添加一些额外的claim。

posted @ 2018-07-29 23:31  wall-ee  阅读(6672)  评论(2编辑  收藏  举报