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中;

相关推荐
努力发光的程序员16 分钟前
互联网大厂Java面试场景:微服务与Spring Cloud技术点解析
spring cloud·grafana·prometheus·微服务架构·jwt·api网关·jaeger
我叫张小白。7 小时前
Spring Boot拦截器详解:实现统一的JWT认证
java·spring boot·web·jwt·拦截器·interceptor
绿荫阿广9 小时前
使用.NET开发并上线一个小智AI对话机器人的MCP服务转接平台
.net·asp.net core·mcp
佛祖让我来巡山2 天前
小明的登录认证鉴权技术漫谈
jwt·token·cookie·session
dephixf10 天前
工业级部署指南:在西门子IOT2050(Debian 12)上搭建.NET 9.0环境与应用部署(进阶篇)
asp.net core·iot·设备管理系统·.net 9·能源管理监控系统
mooyuan天天13 天前
CTFHub Web进阶-Json Web Token通关2:敏感信息泄露
jwt·ctfhub·json web token
星辰h1 个月前
基于JWT的RESTful登录系统实现
前端·spring boot·后端·mysql·restful·jwt
绿荫阿广1 个月前
.NET开发上手Microsoft Agent Framework(一)从开发一个AI美女聊天群组开始
.net·asp.net core·agent framework
止观止1 个月前
JSON Web Token (JWT) 全面解析:原理、优缺点与最佳实践
jwt·1024程序员节·authz·authn
wangbin55421 个月前
使用Scalar.AspNetCore来管理你的OpenApi
asp.net core