注册服务、配置选项、添加身份验证方案

在Startup.ConfigureServices执行services.AddAuthentication()

注册如下服务(便于理解省略了部分辅助服务):

  • services.TryAddScoped<IAuthenticationService, AuthenticationService>();
  • services.TryAddScoped<IAuthenticationHandlerProvider, AuthenticationHandlerProvider>();
  • services.TryAddSingleton<IAuthenticationSchemeProvider, AuthenticationSchemeProvider>();

整个应用的身份验证有个选项对象叫AuthenticationOptions(上一篇有描述),允许我们对身份验证做整体配置,这个配置主要体现为:配置系统需要支持的身份验证方案列表;指定默认身份验证方案、默认登录时用的身份验证方案...默认注销...等。这个对象的应用使用asp.net core的选项模型,我们可以通过AddAuthentication(Action<AuthenticationOptions>)重载来进行配置。参考如下代码:

 services.AddAuthentication(authenticationOptions=> {
  authenticationOptions.AddScheme<CookieAuthenticationHandler>("cookie", "显示名cookie");
  authenticationOptions.AddScheme<JwtBearerHandler>("jwt","显示名jwtToken");
authenticationOptions.DefaultAuthenticateScheme = "cookie";
//...其它配置
});

此重载同样会先注册上面的核心服务。然后设置初始化AuthenticationOptions的委托,当某个类注入AuthenticationOptions时,依赖注入框架会调用此委托来初始化这个选项对象。

另一个重载AddAuthentication(string defaultScheme)内部也是调用上面的方法,只是只设置了AuthenticationOptions.DefaultScheme

AddAuthentication方法始终返回AuthenticationBuilder,它允许我们通过链式调用方式来向AuthenticationOptions添加多个身份验证方案,所以更常见的方式如下:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie().AddJwtBearer();

CookieAuthenticationDefaults.AuthenticationScheme常来指明将哪个身份验证方案作为默认。后续分别添加了cookie和JwtBearer两个身份验证方案。

我们说AuthenticationOptions是针对整个应用程序的身份验证选项,可以简单理解为它是身份验证方案的配置时容器。针对特定身份验证方案也有自己的配置对象。以AddCookie()为例,它等同于:

 authenticationOptions.AddScheme<CookieAuthenticationHandler>(CookieAuthenticationDefaults.AuthenticationScheme, "显示名cookie",);
service.Configre<CookieAuthenticationOptions>(options=>{
options.Cookie.Name = CookieAuthenticationDefaults.CookiePrefix + name;
options.CookieManager = new ChunkingCookieManager();
options.LoginPath = CookieAuthenticationDefaults.LoginPath;
options.LogoutPath = CookieAuthenticationDefaults.LogoutPath;
options.AccessDeniedPath = CookieAuthenticationDefaults.AccessDeniedPath;
}
});

CookieAuthenticationOptions就是针对这个cookie身份验证方案的选项对象,将来某个类注入此选项对象时,依赖注入框架会回调此委托来初始化它。参考:选项模型。当然AddCookie有对应的重载允许我们自己的委托来初始化这个选项对象。类似下面的代码:

 services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie("换个方案名","显示名",opt=> {
opt.SlidingExpiration = true;//滑动过期?
//设置其它跟cookie身份验证相关的东东...
}).AddJwtBearer();

现在看看这段代码就亲切多了。

身份验证方案运行时容器AuthenticationSchemeProvider的建立

由于AuthenticationSchemeProvider是以单例形式注册到依赖注入容器中的,因此应该在注册时(不是很确定,假设吧)就会创建AuthenticationSchemeProvider,它通的构造函数定义了IOptions<AuthenticationOptions>参数,上面说了AuthenticationOptions就包含上面注册进去的身份验证方案列表,AuthenticationSchemeProvider在构造函数中遍历,将所有注册的身份验证方案存储到自身的 IDictionary<string, AuthenticationScheme> _schemes 变量中

插入身份验证中间件

上面只是注册了身份验证过程中需要的服务并配置了应用需要支持身份验证方案列表,在将来请求抵达时需要一个中间件来处理身份验证,核心任务是找到默认身份验证处理器,通过它从请求中获得当前用户标识,然后设置到httpContext.User属性上,至于处理的具体过程将在下一篇基于cookie的身份验证整体流程详细说。在Startup.Configre中通过扩展方法注册:

app.UseRouting();
app.UseAuthentication();
app.UseEndpoints(endpoints =>{
  endpoints.MapRazorPages();
});

至于为啥身份验证中间件一定要在 app.UseRouting(); 之后,我是真的想不通....

05-16 06:56