ASP.NET Core JWT

目录

Session的缺点

[JWT(Json Web Token)](#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

cs 复制代码
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

cs 复制代码
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解码

cs 复制代码
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中;

相关推荐
Amd7946 天前
FastAPI安全认证中的依赖组合
测试用例·fastapi·jwt·依赖注入·权限校验·安全认证·组合依赖
草海桐13 天前
golang 的github.com/dgrijalva/jwt-go包
golang·jwt·jwt-go
EdisonZhou16 天前
使用MCP C# SDK开发MCP Server + Client
llm·aigc·asp.net core·.net core
可爱的霸王龙18 天前
SpringBoot整合JWT
java·后端·jwt
csdn_aspnet1 个月前
在 .NET 9.0 Web API 中实现 Scalar 接口文档及JWT集成
jwt·.net9·scalar
超软毛毛虫1 个月前
ASP.NET Core 模型验证消息的本地化新姿势
asp.net core·localization
图图图图爱睡觉2 个月前
大白话解释认证JWT是什么 有什么用 怎么用
jwt
lixww.cn2 个月前
ASP.NET Core用MediatR实现领域事件
ddd·asp.net core·mediatr
lixww.cn2 个月前
ASP.NET Core SignalR向部分客户端发消息
javascript·websocket·vue·asp.net core·signalr
lixww.cn2 个月前
ASP.NET Core SignalR的协议协商
asp.net core·signalr