这篇文章前前后后改了很多次,都是根据自己对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里面定义了针对上面描述的所有动作方法:

asp.net core 3.0认证详解
 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

相关文章:

  • 2022-02-12
  • 2021-12-04
  • 2021-10-05
  • 2021-08-20
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-08-02
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案