1、 JWT是什么
Json Web Token的简称,是一种安全可靠的身份认证机制。
JWT弥补了Session做为分布式身份认证方面的不足
官方说明:https://jwt.io/introduction
2、 JWT的优势
传统意义上的身份认证,是把认证信息存储到服务器端,比如存储到内存、数据库等。当客户端连接数量过大时,造成了服务端的巨大压力。
而JWT在验证之后是存储在客户端的,减轻了服务器端的压力!
3、 JWT的组成
JWT一般由三段构成,用.号分隔开,第一段是header,第二段是payload,第三段是signature,例如:
xxxxx.yyyyy.zzzzz
1) Header
头部信息,标注了加密信息,如:
{
"alg": "HS256",
"typ": "JWT"
}
2) Payload
主要附带信息,
iss : jwt签发者
sub:jwt所面向的用户
aud:接收jwt的一方
exp:jwt的过期时间,这个过期时间必须要大于签发时间
nbf:定义在什么时间之前,该jwt都是不可用的.
iat :jwt的签发时间
jti :jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
如:
{
"sub": "jsonlee",
"exp": 1623208480
}
3) Signature
签名,即HMACSHA256(base64URLCode(header) ”.” base64URLCode(payload), secret)
完整的例子
首先在Nuget中引入JWT和SinGooCMS.Utility两个包
using System;
using System.Collections.Generic;
using SinGooCMS.Utility;
using System.Security.Cryptography;
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
namespace JWT_Test
{
class Program
{
//密钥
static string secret = "16826375@qq.com";
static void Main(string[] args)
{
//原始的
Console.WriteLine("原始的\r\n");
var headerResult = GetHeaderEncode();
Console.WriteLine("header:" headerResult.Item1 " | header_encode:" headerResult.Item2 "\r\n");
var payloadResult = GetPayloadEncode();
Console.WriteLine("payload:" payloadResult.Item1 " | payload_encode:" payloadResult.Item2 "\r\n");
var signature = GetSignature();
Console.WriteLine("signature:" signature "\r\n");
//使用JWT工具
var payload = new Dictionary<string, object>() {
{ "sub","jsonlee"},
{ "exp",1623208480}
};
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
//加密 身份验证成功后,服务器生成token,并发送到客户端
var token = encoder.Encode(payload, secret);
//FileUtils.CreateFileAsync("c:/jwt.txt", token).GetAwaiter().GetResult();
Console.WriteLine("\r\n 使用JWT工具 \r\n");
Console.WriteLine("token:" token "\r\n");
//解密,客户请求资源时,把token带上,在服务端进行解密
var token2 = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqc29ubGVlIiwiZXhwIjoxNjIzMjA4NDgwfQ.Y-m0knDfE7PsM9TYkwZsuF0A-Ze7kKwblU3MYtK2O24";
IDateTimeProvider provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
var tokenOriginal = decoder.Decode(token2);
Console.WriteLine("\r\n \r\n");
Console.WriteLine("token original:" tokenOriginal "\r\n");
}
#region 原始的JWT分步解析
/*
对照 https://jwt.io/#debugger
检测我们的数据是否正确
*/
private static (string, string) GetHeaderEncode()
{
/*
* base64编码 header头部信息
{
"typ": "JWT",
"alg": "HS256"
}
*/
var header = "{\"typ\":\"JWT\",\"alg\":\"HS256\"}";
return (header, DEncryptUtils.Base64Encrypt(header).Replace(' ', '-').Replace('/', '_').Replace("=", ""));
}
private static (string, string) GetPayloadEncode()
{
/*
iss:jwt签发者
sub:jwt所面向的用户
aud:接收jwt的一方
exp:jwt的过期时间,这个过期时间必须要大于签发时间
nbf:定义在什么时间之前,该jwt都是不可用的.
iat:jwt的签发时间
jti:jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
*/
IDateTimeProvider provider = new UtcDateTimeProvider();
var now = provider.GetNow();
var unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); // or use JwtValidator.UnixEpoch
var secondsSinceEpoch = Math.Round((now - unixEpoch).TotalSeconds);
//var payload = $"{{\"sub\":\"jsonlee\",\"exp\":{secondsSinceEpoch 100}}}";
var payload = "{\"sub\":\"jsonlee\",\"exp\":1623208480}";
return (payload, DEncryptUtils.Base64Encrypt(payload).Replace(' ', '-').Replace('/', '_').Replace("=", ""));
}
private static string GetSignature()
{
// header_encode "." payload_encode
string info = GetHeaderEncode().Item2 "." GetPayloadEncode().Item2;
return SHA256Encrypt(info, secret);
}
#region SHA256加密
/// <summary>
/// HMAC SHA256 (Base64)
/// </summary>
/// <param name="message"></param>
/// <param name="secret"></param>
/// <returns></returns>
public static string SHA256Encrypt(string message, string secret)
{
secret = secret ?? "";
var encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(secret);
byte[] messageBytes = encoding.GetBytes(message);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
return Convert.ToBase64String(hashmessage).Replace(' ', '-').Replace('/', '_').Replace("=", "");
}
}
#endregion
#endregion
}
}
运行后,得出的结果对比
与官网的测试对比