ASP.NET Core之身份认证源码分析
一、前言
在前面的三章节介绍了不同方式的身份认证Cookie、JWT、自定义Token。本章则通过分析ASP.NET Core的身份认证源码内容来探索该框架设计,了解认证过程。在分析源码之前必须具备对ASP.NET Core的服务注册(依赖注入)、中间件、HttpContext、身份元素等内容知识。
上述是对ASP.NET Core中的Claim、ClaimsIdentity、ClaimsPrincipal、AuthenticationTicket等类做一个形象的说明,对应着现实世界的人员身份信息。通过Authentication认证通过之后给用户颁发证书(AuthenticationTicket),证书包含内容正是上述的身份证件载体。
二、类图
上述类图全面描述了ASP.NET Core权限认证的实现方式包括Service、Scheme、Handler、HandlerProvider。在前面的章节中我们完成了默认Cookie/JWT/自定义的方式进行认证,结合类图简单描述认证的具体步骤:
1、在ASP.NET Core中要开启权限认证,首先在容器中注入认证服务,使用services.AddAuthentication,如前面章节注入的认证服务代码
// 定义认证方式(Scheme 架构) builder.Services.AddAuthentication(x => { x.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; x.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; }).AddCookie(option => { //关于Cookie的配置信息请参考:https://www.cnblogs.com/sheldon-lou/p/9545726.html //option.Cookie.Domain = ".contoso.com";//设置Cookie的作用域:他的作用域就包括contoso.com,www.contoso.com option.LoginPath = "/Account/LoginIn"; //在身份验证的时候判断为“未登录”则跳转到这个页面 option.LogoutPath = "/Account/LoginIn";//如果要退出登录则跳转到这个页面 //option.AccessDeniedPath = "/Account/AccessDenied"; //如果已经通过身份验证,但是没有权限访问则跳转到这个页面 option.Cookie.HttpOnly = true;//设置 cookie 是否是只能被服务器访问,默认 true,为true时通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击,窃取cookie内容,这样就增加了cookie的安全性 option.SlidingExpiration = true;//设置Cookie过期时间为相对时间;也就是说在Cookie设定过期的这个时间内用户没有访问服务器,那么cookie就会过期,若有访问服务器,那么cookie期限将从新设为这个时间 option.ExpireTimeSpan = TimeSpan.FromDays(1); //设置Cookie过期时间为1天 option.ClaimsIssuer = "Cookie";//获取或设置应用于创建的任何声明的颁发者 //option.Cookie.Path = "/app1"; //用来隔离同一个服务器下面的不同站点。比如站点是运行在/app1下面,设置这个属性为/app1,那么这个 cookie 就只在 app1下有效。 });
builder.Services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(option =>{ option.TokenValidationParameters = new TokenValidationParameters() { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(builder.Configuration["Jwt:Key"])), ValidateIssuer = false, ValidateAudience = false, }; }); // 自定义认证 builder.Services.AddAuthentication(option => { option.AddScheme<TokenAuthenticationHandler>("token","myToken"); option.DefaultAuthenticateScheme = "token"; option.DefaultForbidScheme = "token"; option.DefaultChallengeScheme = "token"; });
services.AddAuthentication在源码中最重要的其实就是AddAuthenticationCore方法,向容器中注入了认证体系中很重要的对象:IAuthenticationService、IAuthenticationHandlerProvider、IAuthenticationSchemeProvider。
public static IServiceCollection AddAuthenticationCore(this IServiceCollection services) { if (services == null) { throw new ArgumentNullException(nameof(services)); } services.TryAddScoped<IAuthenticationService, AuthenticationService>(); services.TryAddSingleton<IClaimsTransformation, NoopClaimsTransformation>(); // Can be replaced with scoped ones that use DbContext services.TryAddScoped<IAuthenticationHandlerProvider, AuthenticationHandlerProvider>(); services.TryAddSingleton<IAuthenticationSchemeProvider, AuthenticationSchemeProvider>(); return services; }
2、在管道处理中加上需要权限认证app.UseAuthentication(),该方法会向处理管道中添加名为AuthenticationMiddleware的中间件,具体一个请求到来时,框架是如何进行权限认证的处理逻辑都在这里。具体操作如下:
<1>用户请求进入管道的权限认证中,会进入IAuthenticationSchemeProvider对象拿到AuthenticationOptions对象中的IList<AuthenticationSchemeBuilder>集合,所有注册到认证体系中的认证方案都会在该集合中拿到(包括自定义的)。
<2>通过循环集合,调用AuthenticationSchemeBuilder对象的Builder方法去获得所有的认证方案AuthenticationScheme,将得到的AuthenticationScheme以AuthenticationScheme.Name作为key保存到AuthenticationSchemeProvider对象的字典集合IDictionary<string, AuthenticationScheme>中,这样AuthenticationSchemeProvider就拥有了返回AuthenticationScheme的能力,通过传入认证方案名称(服务注册中传入方案名称包括默认的),即可得到方案对象。
<3>拿到了AuthenticationScheme对象,其认证处理类型即可在HandlerType属性中得到(通过认证方案获取认证处理类型),然后在IAuthenticationHandlerProvider的实例对象中根据HandlerType创建一个认证处理对象IAuthenticationHandler,最后调用该对象的AuthenticateAsync方法就是完成具体的认证处理逻辑。需要注意的是这里的IAuthenticationHandler对象会根据每个AuthenticationScheme具备的认证处理逻辑而来,所以得到的AuthenticationScheme不同,认证处理的逻辑就不同。
eg:Cookie为例,我们会在向容器添加认证服务的时候就会指定默认的认证方案名称:service.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme),方法返回AuthenticationBuilder,但此刻还只是组建了认证服务的框架,还需要向这个框架中添加处理认证的方案,所以会通过AuthenticationBuilder.AddCookie将Cooike的认证方案添加进来,当然我们可以添加很多个方案,比如使用JWT进行认证,但实际认证过程还是根据传递的默认方案的名称进行的。
三、总结
通过上述类图构建、源码的分析,ASP.NET Core的权限认证比较清。使用认证方案(AuthenticateScheme)的方式,定义各种认证逻辑(AuthenticateHandler),通过认证逻辑返回认证结果(AuthenticateResult)。举一反三,在探索框架内容时候,可以通过UML的类图、包图、设计模式图来形象展示框架的设计思路,在阅读源码的帮助下完成深入理解框架和涉及的设计模式。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 我与微信审核的“相爱相杀”看个人小程序副业
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求