.NET Core JWT 认证
JWT 介绍
JWT(JSON Web Token)是一种开放标准,它以 JSON 对象的方式在各方之间安全地传输信息。通俗的说,就是通过数字签名算法生产一个字符串,然后在网络请求的中被携带到服务端进行身份认证,功能上来说和 SessionId 认证方式很像。
JWT 与 SessionId 认证对比
SessionId 认证方式一般做法是用户登录成功后,服务端生成一个 SessionId,然后将 SessionId 和 用户的关系进行存储(内存、Redis、数据库等),之后将 SessionId 写入 Cookie(一般是主域名下,方便单点登录) 或返回给调用方,后续的所有请求都携带这个 SessionId 到服务端进行身份认证。

而 JWT 最大区别是登录状态不在服务端进行存储,而是通过密钥生成一个具有有效时间的 Token 返回给前端,Token 中包含类似用户 Id 等信息,且是不允许被篡改的,之后的请求将 Token 携带到服务端进行认证,认证通过后可解析 Token 拿到用户标识进行后续操作。

JWT 构成
Header
header 典型的由两部分组成:token的类型(JWT)和算法名称(HMAC、SHA256、RSA等)
如:
{
"alg": "HS256",
"typ": "JWT"
}
通过 Base64 对这个 JSON 编码就得到 JWT 的第一部分。
Payload
它包含关于实体(通常是用户)和其他数据的声明,分别是 Registered、Public 和 Private 三种类型。
- Registered claims : 预定义的声明,它们不是强制的,但是推荐。如:iss (issuer)、exp (expiration time)、sub (subject)、aud (audience) 等
- Public claims : 可随意定义
- Private claims : 用于在同意使用它们的各方之间共享信息
如:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
通过 Base64 对这个 JSON 编码就得到 JWT 的第二部分。
Signature
Signature用来验证发送请求者身份,由前两部分加密形成。
如:
var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(securityKey));
var encodedSignature = Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(encodedHeader, ".", encodedPayload))));
通过 Header+Payload+Signature 就得到如下结果:

注意:Payload 最终是可以被解析成明文的,所以在设置 Payload 时一定不能将非加密的敏感信息存储在内
JWT 使用方式

- 客户端到认证服务进行认证
- 认证成功返回 Token
- 客户端在请求头中加入 Authorization: Bearer {Token} 访问 API 资源
.NET Core 集成 JWT
搭建 JWTServer
创建 JWTServer(.NET Core Web API)项目 (用来进行身份认证及生成 Token);
Nuget 安装 Microsoft.AspNetCore.Authentication.JwtBearer
配置文件中加入 JWT 相关参数
"JwtSetting": {
"SecurityKey": "d0ecd23c-dfdb-4005-a2ea-0fea210c858a", // 密钥
"Issuer": "jwtIssuertest", // 颁发者
"Audience": "jwtAudiencetest", // 接收者
"ExpireSeconds": 20 // 过期时间(20s)
}
添加用户登录接口,模拟身份认证
private readonly static User User = new User
{
Id = 1,
Name = "beck",
Password = "123456"
};
public async Task<User> LoginAsync(string name, string password)
{
await Task.CompletedTask;
if (User.Name == name && User.Password == password)
{
return User;
}
return null;
}
用户认证成功后获得 User 详细信息,然后生成 Token
public string GetToken(User user)
{
//创建用户身份标识,可按需要添加更多信息
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim("id", user.Id.ToString(), ClaimValueTypes.Integer32), // 用户id
new Claim("name", user.Name), // 用户名
new Claim("admin", user.IsAdmin.ToString(),ClaimValueTypes.Boolean) // 是否是管理员
};
//创建令牌
var token = new JwtSecurityToken(
issuer: _jwtSetting.Issuer,
audience: _jwtSetting.Audience,
signingCredentials: _jwtSetting.Credentials,
claims: claims,
notBefore: DateTime.Now,
expires: DateTime.Now.AddSeconds(_jwtSetting.ExpireSeconds)
);
string jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
return jwtToken;
}
返回 Token 信息
{
"Status": true,
"Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI3Njg1MDUwMS1kZTk5LTRmYmYtYmVlNy01ODAxMjY5ZjNiMTgiLCJpZCI6MSwibmFtZSI6ImJlY2siLCJhZG1pbiI6dHJ1ZSwibmJmIjoxNTUzMzU2MTc1LCJleHAiOjE1NTMzNzYxNzUsImlzcyI6Imp3dElzc3VlcnRlc3QiLCJhdWQiOiJqd3RBdWRpZW5jZXRlc3QifQ.O15rMLMHADGkmhsCNAhcrCMO6c5iQzkXHfbU0jj5HaM",
"Type": "Bearer"
}
将 Token 在 https://jwt.io/ 进行解析查看效果:

搭建 TestApi
创建 TestApi(.NET Core Web API)项目 (模拟需要身份认证的 API 接口)
Nuget 安装 Microsoft.AspNetCore.Authentication.JwtBearer
配置文件中加入 JWT 相关参数
"JwtSetting": {
"SecurityKey": "d0ecd23c-dfdb-4005-a2ea-0fea210c858a", // 密钥
"Issuer": "jwtIssuertest", // 颁发者
"Audience": "jwtAudiencetest" // 接收者
}
Startup 的 ConfigureServices 方法加入如下代码:
var jwtSetting = new JwtSetting();
Configuration.Bind("JwtSetting", jwtSetting);
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = jwtSetting.Issuer,
ValidAudience = jwtSetting.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.SecurityKey)),
// 默认允许 300s 的时间偏移量,设置为0
ClockSkew = TimeSpan.Zero
};
});
Startup 的 Configure 方法加入如下代码:
app.UseAuthentication();
在需要认证的接口上加 [Authorize] 特性
[HttpGet]
[Authorize]
public async Task<string> Get()
{
await Task.CompletedTask;
return $"{_identityService.GetUserId()}:{_identityService.GetUserName()}";
}
public class IdentityService : IIdentityService
{
private readonly IHttpContextAccessor _context;
public IdentityService(IHttpContextAccessor context)
{
_context = context;
}
public int GetUserId()
{
var nameId = _context.HttpContext.User.FindFirst("id");
return nameId != null ? Convert.ToInt32(nameId.Value) : 0;
}
public string GetUserName()
{
return _context.HttpContext.User.FindFirst("name")?.Value;
}
}
使用 Postman 进行测试
请求头不添加 Authorization ,返回 401 状态码:

请求头添加 Authorization,确保 Token 没过期 :

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
2016-07-21 短信验证接口网址
2016-07-21 sql 查询强制使用HASH连接性能测试比较
2016-07-21 了解锁和事务
2016-07-21 Winform开发框架之读卡器和条码扫描枪的数据接收处理
2016-07-21 DevExpress的XtraReport和微软RDLC报表的使用和对比
2016-07-21 sql server日期时间转字符串