
如果你刚学 Minimal API,你会发现:
写接口并不难:
app.MapGet("/hello", () => "hello");但只要一涉及登录、权限、认证,很多概念马上就混在一起:
.RequireAuthorization() 到底是靠什么工作的?很多初学者最大的痛苦不是代码不会写,而是:
概念分不清,所以代码只是“抄会了”,并没有“理解了”。
这篇文章我就按 由浅入深 的方式,把最常见的 3 个东西讲透:
并且重点围绕 ASP.NET Core Minimal API 来讲,不讲空理论。
假设你做了一个系统:
/login 登录/me 获取当前用户信息/orders 查看订单/admin 管理员接口现在有个问题:
用户第一次调用 /login 时,后端知道这是他。
但是用户第二次调用 /me 时,后端凭什么还知道是他?
因为 HTTP 有一个非常重要的特点:
HTTP 是无状态的。
无状态的意思是:
服务器默认不会自动记住上一次请求是谁发的。
也就是说,这两次请求在服务器看来,本来是两件独立的事:
POST /login
GET /me如果没有额外机制,服务器根本不知道:
所以,“登录系统”的本质,就是在解决这个问题:
如何让后续请求能够证明:我就是刚才那个已经登录成功的人。
这就是认证系统存在的意义。
这是所有初学者都必须先分清的两个词。
认证只解决一个问题:
你是谁?
比如:
授权解决的是另一个问题:
你能做什么?
比如:
你一定要先记住:
认证:你是谁
授权:你能做什么并且顺序必须是:
先认证,再授权因为系统连“你是谁”都没确认,就不可能判断“你有没有权限”。
假设你去酒店入住。
你出示身份证,前台确认:
这一步就是 认证。
前台给你一张房卡,房卡上记录了你的入住信息。
以后你再进酒店房间,不需要每次都重新拿身份证,只要刷房卡。
这一步很像:
登录成功后,系统给你一个“凭证”
以后你带着凭证来,系统就能认出你。
这个“凭证”,在 Web 世界里常见的表现方式就是:
很多初学者一上来就被 JWT 吸引,但如果你连 Cookie 都没搞懂,JWT 也很难真的理解。
Cookie 本质上就是:
服务器让浏览器帮忙保存的一小段文本数据。
比如服务器响应时告诉浏览器:
Set-Cookie: UserName=alice浏览器就会把它记住。
之后浏览器再访问这个网站时,会自动带上:
Cookie: UserName=alice所以 Cookie 你可以理解成:
浏览器替你保管的一张小纸条。
Cookie 有几个很重要的特点:
是客户端保存的。
只要满足域名、路径等条件,请求时浏览器会自动把它带给服务器。
Cookie 本身不是登录方案,也不是权限系统。
它只是:
浏览器帮服务器保存和回传数据的一种机制。
在 Minimal API 中,你可以直接操作 Cookie。
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// 写 Cookie
app.MapGet("/set-cookie", (HttpContext context) =>
{
context.Response.Cookies.Append("UserName", "alice");
return "Cookie 已写入";
});
// 读 Cookie
app.MapGet("/get-cookie", (HttpContext context) =>
{
var name = context.Request.Cookies["UserName"];
return $"Cookie 中的 UserName = {name}";
});
app.Run();它说明:
但请注意:
这还不是认证。
这只是“写了一个普通 Cookie”。
你不能因为 Cookie 里写了 UserName=alice,就认为这是一个安全的登录系统。
为什么?
因为用户理论上可以伪造、篡改普通 Cookie。
所以,真正的登录认证,不能只是“随便写个 Cookie”。
这就引出了下一步:
Cookie Authentication
现在我们来讲 Session。
这是很多人最容易误解的概念。
如果说 Cookie 是浏览器上的小纸条,那 Session 可以理解成:
服务器端的一份会话档案。
比如你第一次访问网站时,服务器做两件事:
abc123 abc123 -> 当前用户 alice,验证码 9527,购物车 3 件商品然后服务器把这个编号 abc123 发给浏览器保存。
浏览器下次再来时,把这个编号带回来,服务器一查,就知道你的会话数据了。
Session 的核心思想是:
真正的数据保存在服务器,客户端只保存一个“会话编号”。
所以你可以这么记:
这是最关键的一点。
Session 能帮助你“记住状态”,但它本身不是 ASP.NET Core 标准认证体系中的认证方案。
你当然可以自己这样做:
context.Session.SetString("UserId", "1001");然后每次请求都检查:
var userId = context.Session.GetString("UserId");
if (userId == null) return Unauthorized();这能不能跑?
能。
但这叫:
自己手搓登录状态判断
而不是标准认证体系。
它的问题是:
.RequireAuthorization() 用不上所以你可以把 Session 理解成:
保存会话状态的机制,不是现代 ASP.NET Core 推荐的主认证方案。
Session 更适合存:
不太推荐用来手工维护整个登录认证体系。
var builder = WebApplication.CreateBuilder(args);
// Session 依赖缓存
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
options.Cookie.Name = ".demo.session";
options.IdleTimeout = TimeSpan.FromMinutes(20);
options.Cookie.HttpOnly = true;
});
var app = builder.Build();
app.UseSession();
// 写 Session
app.MapGet("/session/set", (HttpContext context) =>
{
context.Session.SetString("Code", "9527");
return "Session 已写入";
});
// 读 Session
app.MapGet("/session/get", (HttpContext context) =>
{
var code = context.Session.GetString("Code");
return $"Session 中的 Code = {code}";
});
app.Run();访问 /session/set 时:
context.Session.SetString("Code", "9527");ASP.NET Core 会:
Code=9527 存入 Session 数据以后浏览器访问 /session/get 时:
Code=9527前面我们讲了普通 Cookie,也讲了 Session。
现在终于来到 .NET 里真正常见的浏览器认证方案:
Cookie Authentication
普通 Cookie 是:
我手动往浏览器里写一点数据
例如:
context.Response.Cookies.Append("UserName", "alice");这只是写数据。
而 Cookie Authentication 是:
ASP.NET Core 官方提供的标准认证机制,它会把“认证票据”写到 Cookie 中。
注意关键词:
认证票据
它不是简单写一个用户名,而是写入一份由框架保护过的身份信息,然后后续请求能自动恢复出当前用户。
它解决的是:
HttpContext.User 自动有值.RequireAuthorization() 配合换句话说,Cookie Authentication 不是“存值工具”,而是:
ASP.NET Core 里一套完整的浏览器登录认证方案。
流程大概是这样的:
1. 用户提交用户名密码
2. 后端校验账号密码
3. 后端创建 ClaimsPrincipal(用户身份对象)
4. 调用 SignInAsync
5. ASP.NET Core 生成加密/签名后的认证票据,写入 Cookie
6. 浏览器以后每次请求自动带上这个 Cookie
7. ASP.NET Core 从 Cookie 中还原出用户身份
8. 当前请求的 HttpContext.User 就有值了
9. RequireAuthorization() 根据用户身份判断是否允许访问这是 .NET 认证体系中的核心对象。
你可以简单理解成:
当前登录用户的身份对象
里面会有:
比如:
new Claim(ClaimTypes.Name, "alice")
new Claim(ClaimTypes.Role, "admin")
new Claim("user_id", "1001")这些 Claim 最终会组成一个 ClaimsPrincipal。
下面给一个可以直接理解的例子。
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.Cookies;
var builder = WebApplication.CreateBuilder(args);
// 1. 注册认证:默认使用 Cookie 认证
builder.Services
.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.Name = "demo_auth_cookie";
// 对 API 来说,不要跳转到登录页,直接返回 401
options.Events.OnRedirectToLogin = context =>
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return Task.CompletedTask;
};
});
// 2. 注册授权
builder.Services.AddAuthorization();
var app = builder.Build();
// 3. 启用认证和授权中间件
app.UseAuthentication();
app.UseAuthorization();
// 公开接口
app.MapGet("/", () => "任何人都能访问");
// 登录接口
app.MapPost("/login", async (HttpContext context) =>
{
// 实际项目里这里应该校验数据库用户名密码
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, "alice"),
new Claim(ClaimTypes.Role, "admin"),
new Claim("user_id", "1001")
};
var identity = new ClaimsIdentity(
claims,
CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
await context.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
principal);
return Results.Ok("登录成功");
});
// 当前用户信息
app.MapGet("/me", (ClaimsPrincipal user) =>
{
return Results.Ok(new
{
IsAuthenticated = user.Identity?.IsAuthenticated,
Name = user.Identity?.Name,
Claims = user.Claims.Select(c => new { c.Type, c.Value })
});
}).RequireAuthorization();
// 退出登录
app.MapPost("/logout", async (HttpContext context) =>
{
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return Results.Ok("已退出登录");
});
app.Run();AddAuthentication().AddCookie()表示:
系统要启用 Cookie 认证方案。
SignInAsync表示:
当前用户登录成功,请把他的身份写入认证 Cookie。
HttpContext.User在用户后续请求时,ASP.NET Core 会自动从认证 Cookie 里恢复用户身份,所以这里能拿到用户信息。
.RequireAuthorization()表示:
这个接口只有“已经通过认证”的用户才能访问。
它最适合:
为什么?
因为浏览器会自动带 Cookie,所以体验自然。
它也不是万能的。
它天然更适合浏览器,不太适合 App、小程序、第三方调用。
因为浏览器会自动带 Cookie,所以要防跨站请求伪造。
现在我们再来讲 JWT。
当你理解了 Cookie Authentication,你就会发现 JWT 其实只是另一种“携带身份凭证”的方式。
JWT 全称是:
JSON Web Token
你可以暂时把它理解成:
服务器签发给客户端的一张“令牌”
客户端以后每次请求时,都主动带着这张令牌,告诉服务器:
你看,我已经登录过了,这是我的身份证明。
例如:
Authorization: Bearer eyJhbGciOi...JWT 看起来像这样:
xxxxx.yyyyy.zzzzz它通常由三部分组成:
JWT 里带着用户身份信息,并且有签名,服务器可以验证它有没有被伪造。
流程如下:
1. 用户提交用户名密码
2. 服务器校验成功
3. 服务器生成一个 JWT
4. 把 JWT 返回给客户端
5. 客户端保存 JWT
6. 后续每次请求,把 JWT 放进 Authorization 头
7. 服务器校验 JWT 是否有效
8. 如果有效,就恢复出当前用户身份因为在前后端分离场景中:
这时候让客户端自己在 Header 中带 Token,会比依赖浏览器 Cookie 更灵活。
所以 JWT 常见于:
先安装包:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer然后写代码:
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
var builder = WebApplication.CreateBuilder(args);
var secretKey = "this_is_demo_secret_key_123456789_123456";
var issuer = "minimal-api-demo";
var audience = "minimal-api-client";
// 1. 注册 JWT 认证
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = issuer,
ValidateAudience = true,
ValidAudience = audience,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(secretKey)),
ValidateLifetime = true
};
});
// 2. 注册授权
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
// 登录接口:生成 JWT
app.MapPost("/login", () =>
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, "alice"),
new Claim(ClaimTypes.Role, "admin"),
new Claim("user_id", "1001")
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: issuer,
audience: audience,
claims: claims,
expires: DateTime.UtcNow.AddMinutes(30),
signingCredentials: credentials);
var jwt = new JwtSecurityTokenHandler().WriteToken(token);
return Results.Ok(new
{
access_token = jwt
});
});
// 受保护接口
app.MapGet("/me", (ClaimsPrincipal user) =>
{
return Results.Ok(new
{
IsAuthenticated = user.Identity?.IsAuthenticated,
Name = user.Identity?.Name,
Claims = user.Claims.Select(c => new { c.Type, c.Value })
});
}).RequireAuthorization();
app.Run(); var token = new JwtSecurityToken(...)表示创建一个 JWT,里面放了用户 Claim 和过期时间。
return Results.Ok(new { access_token = jwt });表示后端把登录令牌返回给前端。
请求头示意:
Authorization: Bearer 你的tokenJWT Bearer 中间件会自动:
验证通过后,把用户身份放到 HttpContext.User。
这是新手非常爱问的问题。
但正确答案不是“谁更高级”,而是:
谁更适合当前场景。
更适合:
因为浏览器自动带 Cookie,使用体验非常自然。
更适合:
因为它和客户端类型解耦,不依赖浏览器自动带 Cookie。
Cookie Authentication 更像:
浏览器“自动带工牌”
JWT 更像:
客户端“每次主动出示令牌”
这是最容易混的地方,我们专门理一遍。
浏览器存一小段数据。
服务端存一份会话数据,通常浏览器通过 Cookie 带一个 SessionId 来找到它。
ASP.NET Core 官方认证方案。 它把认证票据写进 Cookie,后续请求自动恢复用户身份。
服务器签发 Token,客户端自己保存,请求时手动带上。
项目 | Session | 普通 Cookie | Cookie Authentication | JWT |
|---|---|---|---|---|
是什么 | 服务端会话数据机制 | 浏览器保存数据的机制 | ASP.NET Core 标准认证方案 | Token 认证方案 |
数据主要存哪 | 服务端 | 客户端浏览器 | 认证票据通常在客户端 Cookie | 客户端 |
是否是“认证方案” | 不是 | 不是 | 是 | 是 |
浏览器会不会自动带 | SessionId 通常会自动带 | 会 | 会 | 不会,需手动放 Header |
适合浏览器网站 | 可以辅助 | 一般 | 很适合 | 可以,但未必最优 |
适合前后端分离 | 不适合 | 不适合 | 一般 | 很适合 |
适合 App / 小程序 | 不适合 | 不适合 | 一般 | 很适合 |
是否依赖服务端存状态 | 是 | 否 | 通常较少依赖 | 否 |
在 .NET 中是否有标准支持 | 有 | 有 | 有 | 有 |
直接给你最实用的结论。
优先选:
Cookie Authentication
理由:
优先选:
JWT
理由:
用:
Session
但别把它当成完整认证方案。
很多人照着写,但不知道为什么。
我用最直白的话解释。
builder.Services.AddAuthentication()意思是:
我要启用 ASP.NET Core 认证系统。
.AddCookie() / .AddJwtBearer()意思是:
我要告诉框架,用哪种方式来识别当前用户。
AddCookie():通过 Cookie 认证AddJwtBearer():通过 Bearer Token 认证builder.Services.AddAuthorization()意思是:
我要启用授权系统,这样才能用
.RequireAuthorization()。
app.UseAuthentication()意思是:
每次请求进来时,先尝试识别当前用户是谁。
app.UseAuthorization()意思是:
在识别出用户之后,再判断他有没有权限访问接口。
.RequireAuthorization()意思是:
这个接口必须是已经认证通过的用户才能访问。
你发送短信验证码后,想把验证码临时存起来。
适合:
Session
因为这是临时状态,不是标准登录身份。
管理员在浏览器中登录,之后点击各种页面和接口。
适合:
Cookie Authentication
因为浏览器自动带 Cookie,最自然。
前端登录后拿到 Token,之后调用所有 API。
适合:
JWT
因为前后端分离,前端自己控制 Header 更灵活。
错。
Session 是会话数据机制,不是标准认证方案。
错。
普通 Cookie 只是存数据。 只有 Cookie Authentication 才是标准认证方案。
错。
JWT 不是更高级,只是更适合前后端分离和多终端场景。
如果你是浏览器后台系统,Cookie Authentication 往往更合适。
.RequireAuthorization()错。
.RequireAuthorization() 依赖 ASP.NET Core 认证体系,不是看你 Session 里有没有 UserId。
UseAuthentication() 要在 UseAuthorization() 前面必须这样写:
app.UseAuthentication();
app.UseAuthorization();因为要先知道“你是谁”,才能判断“你能不能访问”。
开发环境可以:
AddDistributedMemoryCache()但生产环境多实例部署时,最好用 Redis 等共享存储。
如果你是 App、小程序、开放 API,就别硬上 Cookie。
不要发一个永不过期的 JWT。
最起码要有过期时间,后续再学 RefreshToken。
如果你现在还是有点乱,我用最白话的方式再总结一次。
服务端帮你存一份会话数据,浏览器通常只带一个编号回来。
适合存临时状态,不推荐手搓完整登录系统。
浏览器保存的一小段数据,请求时会自动带上。
它只是载体,不是完整认证方案。
ASP.NET Core 官方提供的浏览器登录认证机制,它把认证票据写进 Cookie。
适合后台系统、企业网站、浏览器场景。
服务器签发给客户端的令牌,客户端以后每次请求主动带上。
适合前后端分离、App、小程序、开放 API。
如果你现在就要做项目,可以按这个最简单标准来:
选:
Cookie Authentication选:
JWT选:
Session答案是:
能手搓,但不推荐。现代 ASP.NET Core 更推荐 Cookie Authentication 或 JWT。场景 | 推荐方案 |
|---|---|
验证码、购物车、临时流程状态 | Session |
浏览器后台、企业内部系统 | Cookie Authentication |
Vue / React 前后端分离 | JWT |
App / 小程序 | JWT |
传统 Web 登录 | Cookie Authentication |
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。