重要对象
JwtSecurityToken
代表一个jwt token,可以直接用此对象生成token字符串,也可以使用token字符串创建此对象
SecurityToken
JwtSecurityToken的基类,包含基础数据
JwtSecurityTokenHandler
创建、校验token,返回ClaimsPrincipal
CanReadToken():确定字符串是否是格式良好的Json Web令牌(JWT)
ReadJwtToken(string token):token字符串转为JwtSecurityToken对象
ValidateToken(string token、TokenValidationParameters parameter,out SecurityToken validatedToken):校验token,返回ClaimsIdentity,
方式1(推荐)
引用NuGet包:System.IdentityModel.Tokens.Jwt
static void Main(string[] args)
{
//引用System.IdentityModel.Tokens.Jwt
DateTime utcNow = DateTime.UtcNow;
string key = "f47b558d-7654-458c-99f2-13b190ef0199";
SecurityKey securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(key));
var claims = new List<Claim>() {
new Claim("ID","1"),
new Claim("Name","fan")
};
JwtSecurityToken jwtToken = new JwtSecurityToken(
issuer: "fan",
audience: "audi~~!",
claims: claims,
notBefore: utcNow,
expires: utcNow.AddYears(1),
signingCredentials: new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256)
);
//生成token方式1
string token1 = new JwtSecurityTokenHandler().WriteToken(jwtToken);
//A Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor that contains details of contents of the token.
var tokenDescriptor = new SecurityTokenDescriptor // 创建一个 Token 的原始对象
{
Issuer = "fan",
Audience = "audi",
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, "")
}),
Expires = DateTime.Now.AddMinutes(60),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(key)), SecurityAlgorithms.HmacSha256)
};
//生成token方式2
SecurityToken securityToken = new JwtSecurityTokenHandler().CreateToken(tokenDescriptor);
var token2 = new JwtSecurityTokenHandler().WriteToken(securityToken);
//校验token
var validateParameter = new TokenValidationParameters()
{
ValidateLifetime = true,
ValidateAudience = true,
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "fan",
ValidAudience = "audi~~!",
IssuerSigningKey = securityKey,
};
//不校验,直接解析token
//jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token1);
try
{
//校验并解析token
var claimsPrincipal = new JwtSecurityTokenHandler().ValidateToken(token1, validateParameter, out SecurityToken validatedToken);//validatedToken:解密后的对象
var jwtPayload = ((JwtSecurityToken)validatedToken).Payload.SerializeToJson(); //获取payload中的数据
}
catch (SecurityTokenExpiredException)
{
//表示过期
}
catch (SecurityTokenException)
{
//表示token错误
}
}
方式2
引用Nuget包:JWT
/// <summary>
/// 创建token
/// </summary>
/// <returns></returns>
public static string CreateJwtToken(IDictionary<string, object> payload, string secret, IDictionary<string, object> extraHeaders = null)
{
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
var token = encoder.Encode(payload, secret);
return token;
}
/// <summary>
/// 校验解析token
/// </summary>
/// <returns></returns>
public static string ValidateJwtToken(string token, string secret)
{
try
{
IJsonSerializer serializer = new JsonNetSerializer();
IDateTimeProvider provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtAlgorithm alg = new HMACSHA256Algorithm();
IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, alg);
var json = decoder.Decode(token, secret, true);
//校验通过,返回解密后的字符串
return json;
}
catch (TokenExpiredException)
{
//表示过期
return "expired";
}
catch (SignatureVerificationException)
{
//表示验证不通过
return "invalid";
}
catch (Exception)
{
return "error";
}
}
//-------------客户端调用---------------
public static void Main(string[] args)
{
var sign = "123";
var extraHeaders = new Dictionary<string, object>
{
{ "myName", "limaru" },
};
//过期时间(可以不设置,下面表示签名后 10秒过期)
double exp = (DateTime.UtcNow.AddSeconds(10) - new DateTime(1970, 1, 1)).TotalSeconds;
var payload = new Dictionary<string, object>
{
{ "userId", "001" },
{ "userAccount", "fan" },
{ "exp",exp }
};
var token = CreateJwtToken(payload, sign, extraHeaders);
var text = ValidateJwtToken(token, sign);
Console.ReadKey();
}
方式3
手写jwt算法
JWT组成
样式:"xxxxxxxxxxxx.xxxxxxxxxxxxx.xxxxxxxxxxxxxxxx"由三部分组成.
(1).Header头部:{"alg":"HS256","typ":"JWT"}基本组成,也可以自己添加别的内容,然后对最后的内容进行Base64编码.
(2).Payload负载:iss、sub、aud、exp、nbf、iat、jti基本参数,也可以自己添加别的内容,然后对最后的内容进行Base64编码.
(3).Signature签名:将Base64后的Header和Payload通过.组合起来,然后利用Hmacsha256+密钥进行加密。
#region Base64编码
2 /// <summary>
3 /// Base64编码
4 /// </summary>
5 /// <param name="text">待编码的文本字符串</param>
6 /// <returns>编码的文本字符串</returns>
7 public string Base64UrlEncode(string text)
8 {
9 var plainTextBytes = Encoding.UTF8.GetBytes(text);
10 var base64 = Convert.ToBase64String(plainTextBytes).Replace('+', '-').Replace('/', '_').TrimEnd('=');
11 return base64;
12 }
13 #endregion
14
15 #region Base64解码
16 /// <summary>
17 /// Base64解码
18 /// </summary>
19 /// <param name="base64UrlStr"></param>
20 /// <returns></returns>
21
22 public string Base64UrlDecode(string base64UrlStr)
23 {
24 base64UrlStr = base64UrlStr.Replace('-', '+').Replace('_', '/');
25 switch (base64UrlStr.Length % 4)
26 {
27 case 2:
28 base64UrlStr += "==";
29 break;
30 case 3:
31 base64UrlStr += "=";
32 break;
33 }
34 var bytes = Convert.FromBase64String(base64UrlStr);
35 return Encoding.UTF8.GetString(bytes);
36 }
#endregion Base64编码和解码
/// <summary>
/// 手写JWT算法
/// </summary>
public bool TestJwt1()
{
string secretKey = Configuration["SecretKey"];
//1.加密
//1.1 表头的处理
string headerBase64Url = this.Base64UrlEncode("{\"alg\":\"HS256\",\"typ\":\"JWT\"}");
//1.2 PayLoad的处理
var jwtPayLoad = new
{
expire = DateTime.Now.AddMinutes(15),
userId = "00000000001",
userAccount = "admin"
};
string payloadBase64Url = this.Base64UrlEncode(JsonConvert.SerializeObject(jwtPayLoad));
//1.3 Sign的处理
string sign = $"{headerBase64Url}.{payloadBase64Url}".HMACSHA256(secretKey);
//1.4 最终的jwt字符串
string jwtStr = $"{headerBase64Url}.{payloadBase64Url}.{sign}";
//2.校验token是否正确
bool result; //True表示通过,False表示未通过
//2.1. 获取token中的PayLoad中的值,并做过期校验
JwtData myData = JsonConvert.DeserializeObject<JwtData>(this.Base64UrlDecode(jwtStr.Split('.')[1])); //这一步已经获取到了payload中的值,并进行转换了
var nowTime = DateTime.Now;
if (nowTime > myData.expire)
{
//表示token过期,校验未通过
result = false;
return result;
}
else
{
//2.2 做准确性校验
var items = jwtStr.Split('.');
var oldSign = items[2];
string newSign = $"{items[0]}.{items[1]}".HMACSHA256(secretKey);
result = oldSign == newSign; //true表示检验通过,false表示检验未通过
return result;
}
}
参考: