重要對象
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;
}
}
參考: