.NET CORE 认证模块-Cookie、JWT 与自定义 Scheme 框架为我们提供了很多默认的实现在做一些中小项目在不涉及OIDC不构建身份认证中心的场景下通常选择使用Cookie和JWT的方式。同时框架内置了其他的一些实现例如基于oAuth2.0的实现包括谷歌、Facebook、GitHub等用于支持第三方登录。在我们日常开发场景下可能会接触使用一些飞书、微信等第三方登录但是原生框架中并没有直接提供实现。因为他们也遵循 oAuth2.0协议标准的我们可以自己封装集成进框架中注意是实现授权码流程还有其他几种流程模式可能不支持如果要区分出他们有什么不同的话可能需要搞清楚一些概念。1. 什么是OIDC2.什么是oAuth2.0?这里就不多做介绍比较偏理论理解串起来很头疼但是个人觉得还是得静下心来找一些书籍或者项目自己研究下不要草草的复制粘贴进AI工具回答的快忘记的也快AI作为辅助还可以成体系还是得自己梳理。2. 使用Cookie的认证方式在介绍之前我们必须先搞清楚一个概念有状态和无状态一句话就是指的是服务端要不要保存会话下面是无状态的请求流程和特点。特点服务端没有会话记录重启应用不影响已发出的 Cookie密钥还在就行退出登录 只删浏览器 Cookie服务端没有会话别人复制 Cookie在你退出登录前可能还有效多实例部署比较简单每台机器有一样的密钥就行因为Claims 都在里面所以Cookie 很长下面是有状态流程和特点特点服务端有会话记录能强制下线、踢人、查在线。退出登录 删服务端会话 清 Cookie旧 Cookie 立刻失效。多实例部署要 Redis 等共享存储否则会话查不到。Cookie 通常比无状态略短但还是长密文不是理解的那种guid那种。应用重启如果在内存的话会话全丢用户要重新登录。可以对比表格看下对比维度无状态默认 AddCookie有状态SessionStore / ITicketStore服务端是否存会话不存存内存 / Redis / DBCookie 里主要是什么加密后的完整 Ticket含 Claims加密后的会话引用SessionId每次请求怎么认人解密 Cookie → 直接得到 User解密 Cookie → 拿 SessionId → 查服务端 → 得到 User.NET Core 的 Cookie 认证方案在默认配置下是无状态的服务端不会存储认证票据服务端只需要从 HTTP 请求中读取 Cookie使用TicketDataFormat解密验证票据是否过期当然也可以使用有状态主要用于处理票据很大超过浏览器Cookie大小限制或需要做即时撤销的场景例如服务端踢人下线又或者是需要在多个服务实例间共享会话状态。我们先介绍在NETCORE中Cookie认证使用无状态模式怎么做。2.1 无状态Cookie集成思路第一步注册身份认证核心服务需要先在Program注册身份认证的核心服务以及常规配置使中间件可以调用对应服务。var authenticationBuilder builder.Services.AddAuthentication(options { // 设置默认的身份验证方案用于验证用户身份 // 当控制器未显式指定 AuthenticationSchemes 时系统自动使用 Cookie 方案 options.DefaultAuthenticateScheme CookieAuthenticationDefaults.AuthenticationScheme; // 设置默认的质询方案用于触发登录流程 // 当未认证用户访问受保护资源时系统自动重定向到 Cookie 登录流程 options.DefaultChallengeScheme CookieAuthenticationDefaults.AuthenticationScheme; // 要求用户必须通过 SignInManager.SignInAsync() 完成登录 // 防止仅通过 ClaimsPrincipal 构造的伪登录绕过安全检查 options.RequireAuthenticatedSignIn true; });第二步将Cookie认证方案和它的配置注入容器// 添加Cookie 身份验证方案 authenticationBuilder.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options { // 设置 Cookie 的名称浏览器中显示为 CodeSource.Auth // 不同应用必须使用唯一名称避免跨站冲突 options.Cookie.Name CodeSource.Auth; options.Cookie.HttpOnly true; options.ExpireTimeSpan TimeSpan.FromHours(8); // 过期时间 options.SlidingExpiration true; // 滑动过期 // 针对没认证但是访问资源将原本的重定向改为直接返回 401 options.Events.OnRedirectToLogin context { context.Response.StatusCode StatusCodes.Status401Unauthorized; return Task.CompletedTask; }; // 针对登录了但是没权限访问资源将原本的重定向改为直接返回 403 // 避免前端因重定向丢失原始请求上下文 options.Events.OnRedirectToAccessDenied context { context.Response.StatusCode StatusCodes.Status403Forbidden; return Task.CompletedTask; }; });第三步注册中间件通过app.UseXXX()方法将认证与授权中间件按顺序加入请求处理管道这里需要注意顺序先认证再授权所以中间件必须也要这样定义。至于为什么可以自行去补充下基础知识。var app builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); } app.UseHttpsRedirection(); app.UseSwaggerUI(); // 添加认证中间件 app.UseAuthentication(); // 添加授权中间件 app.UseAuthorization(); app.MapControllers(); app.Run();第四步在控制器中使用注意标记Authorize特性然后认证Scheme选择Cookie的方式。括号中的如果只有一种认证方式可以不写因为在前面配置时设置了默认方案。[ApiController] [Route([controller])] [Authorize(AuthenticationSchemes CookieAuthenticationDefaults.AuthenticationScheme)] public class UserController : ControllerBase { private static readonly User[] Users [ new User { Id 1, Name 张三, Email zhangsanexample.com }, new User { Id 2, Name 李四, Email lisiexample.com }, new User { Id 3, Name 王五, Email wangwuexample.com } ]; [HttpGet(Name GetUsers)] public IEnumerable Get() { return Users; } }