当前位置: 首页 > article >正文

ASP.NET Core JWT

目录

Session的缺点

JWT(Json Web Token)

优点:

登录流程

JWT的基本使用

生成JWT

解码JWT

用JwtSecurityTokenHandler对JWT解码

注意


Session的缺点

  1. 对于分布式集群环境,Session数据保存在服务器内存中就不合适了,应该放到一个中心状态服务器上。ASP.NET Core支持Session采用Redis、Memcached。
  2. 中心状态服务器有性能问题。

JWT(Json Web Token)

  1. JWT把登录信息(也称作令牌)保存在客户端。
  2. 为了防止客户端的数据造假,保存在客户端的令牌经过了签名处理,而签名的密钥只有服务器端才知道,每次服务器端收到客户端提交过来的令牌的时候都要检查一下签名。

优点:

  1. 状态保存在客户端,适合分布式系统。
  2. 签名保证了客户端无法数据造假。
  3. 性能更高,不需要和中心状态服务器通讯,纯内存计算。

登录流程

  1. 客户端向服务器端发送用户名,密码等请求登录。
  2. 服务器端校验用户名,密码,如果校验成功,则从数据库中取出这个用户的ID、角色等用户相关信息。
  3. 服务器端采用只有服务器端才知道的密钥来对用户信息的JSON字符串进行签名,形成签名数据。
  4. 服务器端把用户信息的JSON字符串和签名拼接到一起形成JWT,然后发送给客户端。
  5. 客户端保存服务器端返回的JWT,并且在客户端每次向服务器端发送请求的时候都带上这个JWT。
  6. 每次服务器端收到浏览器请求中携带的JWT后,服务器端用密钥对JWT的签名进行校验,如果校验成功,服务器端则从JWT中的JSON字符串中读取用户的信息。这样服务器端就知道这个请求对应的用户了。

JWT的基本使用

NuGet:System.IdentityModel.Tokens.Jwt

生成JWT

using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

//claim是一个键值对,用来存储用户信息,比如用户id,用户名,角色等
var claims = new List<Claim>()
{
    new Claim(ClaimTypes.NameIdentifier, "123"),
    new Claim(ClaimTypes.Name, "ljy"),
    new Claim(ClaimTypes.Role, "admin"),
    new Claim(ClaimTypes.Role, "user"),
    new Claim("Passport", "E90000082"),
    new Claim("Id", "E90000082")
};
string key = "jddsjf54$$%45445%^$gvdfgd8d454dgji34jk";
//设置过期时间,30分钟后过期
DateTime expires = DateTime.Now.AddMinutes(30);
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
//对称秘钥
var secKey = new SymmetricSecurityKey(keyBytes);
//签名凭据
var credentials = new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature);
//创建jwtSecurityToken
var tokenDescriptor = new JwtSecurityToken(
    claims: claims,//声明
    expires: expires,//过期时间
    signingCredentials: credentials//签名凭据
    );
//生成token
string jwt = new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
Console.WriteLine(jwt);

解码JWT

using System.Text;

string jwt = "eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjEyMyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJsankiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsiYWRtaW4iLCJ1c2VyIl0sIlBhc3Nwb3J0IjoiRTkwMDAwMDgyIiwiSWQiOiJFOTAwMDAwODIiLCJleHAiOjE3Mzg4MzAxMTB9.frI1BwyedlIfuIcWgkxfNsbXkaJJ01M3iNo7wXt6Fy8";

string[] strs = jwt.Split('.');
string header = JwtDecode(strs[0]);
string payload = JwtDecode(strs[1]);
Console.WriteLine("---head---");
Console.WriteLine(header);
Console.WriteLine("---payload---");
Console.WriteLine(payload);

string JwtDecode(string s)
{
    s = s.Replace('-', '+').Replace('_', '/');
    switch (s.Length % 4)
    {
        case 2:
            s += "==";
            break;
        case 3:
            s += "=";
            break;
    }
    var bytes = Convert.FromBase64String(s);
    return Encoding.UTF8.GetString(bytes);
}

用JwtSecurityTokenHandler对JWT解码

using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

string jwt = "eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjEyMyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJsankiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsiYWRtaW4iLCJ1c2VyIl0sIlBhc3Nwb3J0IjoiRTkwMDAwMDgyIiwiSWQiOiJFOTAwMDAwODIiLCJleHAiOjE3Mzg4MzAxMTB9.frI1BwyedlIfuIcWgkxfNsbXkaJJ01M3iNo7wXt6Fy8";


string secKey = "jddsjf54$$%45445%^$gvdfgd8d454dgji34jk";
JwtSecurityTokenHandler tokenHandler = new();
//设置验证参数
TokenValidationParameters valParam = new();
SymmetricSecurityKey securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secKey));
//获取或设置用于签名验证的 SecurityKey
valParam.IssuerSigningKey = securityKey;
//不验证发行者
valParam.ValidateIssuer = false;
//不验证接受者
valParam.ValidateAudience = false;
ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(jwt,
            valParam, out SecurityToken secToken);
foreach (Claim claim in claimsPrincipal.Claims)
{
    Console.WriteLine($"{claim.Type}={claim.Value}");
}

注意

负载中的内容是明文形式保存的;
不要把不能被客户端知道的信息放到JWT中;


http://www.kler.cn/a/535690.html

相关文章:

  • 探索 GraphQL:API 设计的未来趋势
  • 网络编程day1
  • 4. Go结构体使用
  • 机器学习-线性回归(参数估计之结构风险最小化)
  • 在VS Code中基于TypeScript使用Vue.js搭建Babylon.js的开发环境
  • 【Rust自学】16.4. 通过Send和Sync trait来扩展并发
  • DeepSeek 引发 AI 大模型战火,编程语言群雄激战谁夺胜利权杖?
  • 4G核心网的演变与创新:从传统到虚拟化的跨越
  • e2studio开发RA2E1(8)----GPT定时器频率与占空比的设置
  • 3. 【.NET Aspire 从入门到实战】--理论入门与环境搭建--环境搭建
  • SpringBoot开发(五)SpringBoot接收请求参数
  • 【数据结构】单向链表(真正的零基础)
  • 六。自定义数据集 使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测
  • 虚拟机报错:处理器未启用 NX/XD,而 VMware Workstation 要求启用 NX/XD.没有可打开电源的虚拟机
  • k8sollama部署deepseek-R1模型,内网无坑
  • 【Leetcode 热题 100】72. 编辑距离
  • 【2025最新计算机毕业设计】基于springboot智能教师评价系统【提供源码+答辩PPT+文档+项目部署】(高质量源码,可定制,提供文档,免费部署到本地)
  • 深入理解C++的new和delete
  • linux 使用docker安装 postgres 教程,踩坑实践
  • Unity3D 切线空间及其应用详解
  • springboot011-G县乡村生活垃圾治理问题中运输地图系统
  • 网络安全配置
  • 从源码到上线:AI在线教育系统开发全流程与网校APP构建指南
  • 使用 TensorRT 和 Python 实现高性能图像推理服务器
  • LeetCode 415
  • 无人机使用数传时的注意事项!