最近在開發項目中,為了便于操作jwt,自己封裝了一個jwthelper,發出來,供大家一起讨論。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5yY1ETNllTNhFWM5QGOiBDMjlTYkVzNmNjZ5MjNwczMz8CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
using Microsoft.AspNetCore.Http;using Microsoft.IdentityModel.Tokens;using Newtonsoft.Json;using System;using System.Collections.Generic;using System.IdentityModel.Tokens.Jwt;using System.Linq;using System.Security.Claims;using System.Text;using System.Text.RegularExpressions;using TianFeng.FrameworkCore.Extensions;namespace TFCMS.Tools{ //iss: jwt簽發者 //sub: jwt所面向的使用者 //aud: 接收jwt的一方 //exp: jwt的過期時間,這個過期時間必須要大于簽發時間 //nbf: 定義在什麼時間之前,該jwt都是不可用的. //iat: jwt的簽發時間 //jti: jwt的唯一身份辨別,主要用來作為一次性token,進而回避重播攻擊。 //var jwt_id = User.Claims.FirstOrDefault(p => p.Type == "jti").Value; //User.Claims.Select(p => new { p.Type, p.Value /// /// Jwt設定 /// public class JwtSettings { /// /// 發行人 /// public string Issuer { get; set; } /// /// 訂閱者 /// public string Audience { get; set; } /// /// 加密key /// public string SecurityKey { get; set; } /// /// 過期分鐘 /// public int ExpMinutes { get; set; } } /// /// Jwt載荷資訊 /// public class JwtPayload { public string UserId { get; set; } public string UserName { get; set; } public string RoleId { get; set; } public DateTime ExpTime { get; set; } } /// /// Jwt幫助類 /// public static class JwtHelper { private static JwtSettings settings; public static JwtSettings Settings { set { settings = value; } get { return settings; } } /// /// 生成token /// /// /// public static string CreateToken(IEnumerable claims) { var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(settings.SecurityKey)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var securityToken = new JwtSecurityToken( issuer: settings.Issuer, audience: settings.Audience, claims: claims, //expires: DateTime.Now.AddMinutes(settings.ExpMinutes), signingCredentials: creds); var token = new JwtSecurityTokenHandler().WriteToken(securityToken); return token; } /// /// 生成Jwt /// /// /// /// /// public static string CreateToken(string userName, string roleId, string userId) { //聲明claim var claims = new Claim[] { new Claim(JwtRegisteredClaimNames.Sub, userName), new Claim(JwtRegisteredClaimNames.Jti, userId), new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToUnixDate().ToString(), ClaimValueTypes.Integer64),//簽發時間 new Claim(JwtRegisteredClaimNames.Nbf, DateTime.UtcNow.ToUnixDate().ToString(), ClaimValueTypes.Integer64),//生效時間 new Claim(JwtRegisteredClaimNames.Exp, DateTime.Now.AddMinutes(settings.ExpMinutes).ToUnixDate().ToString(), ClaimValueTypes.Integer64), //過期時間 new Claim(JwtRegisteredClaimNames.Iss, settings.Issuer), new Claim(JwtRegisteredClaimNames.Aud, settings.Audience), new Claim(ClaimTypes.Name, userName), new Claim(ClaimTypes.Role, roleId), new Claim(ClaimTypes.Sid, userId) }; return CreateToken(claims); } /// /// 重新整理token /// /// public static string RefreshToken(string oldToken) { var pl = GetPayload(oldToken); //聲明claim var claims = new Claim[] { new Claim(JwtRegisteredClaimNames.Sub, pl?.UserName), new Claim(JwtRegisteredClaimNames.Jti, pl?.UserId), new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToUnixDate().ToString(), ClaimValueTypes.Integer64),//簽發時間 new Claim(JwtRegisteredClaimNames.Nbf, DateTime.UtcNow.ToUnixDate().ToString(), ClaimValueTypes.Integer64),//生效時間 new Claim(JwtRegisteredClaimNames.Exp, DateTime.Now.AddMinutes(settings.ExpMinutes).ToUnixDate().ToString(), ClaimValueTypes.Integer64), //過期時間 new Claim(JwtRegisteredClaimNames.Iss, settings.Issuer), new Claim(JwtRegisteredClaimNames.Aud, settings.Audience), new Claim(ClaimTypes.Name, pl?.UserName), new Claim(ClaimTypes.Role, pl?.RoleId), new Claim(ClaimTypes.Sid, pl?.UserId) }; return IsExp(oldToken) ? CreateToken(claims) : null; } /// /// 從token中擷取使用者身份 /// /// /// public static IEnumerable GetClaims(string token) { var handler = new JwtSecurityTokenHandler(); var securityToken = handler.ReadJwtToken(token); return securityToken?.Claims; } /// /// 從Token中擷取使用者身份 /// /// /// public static ClaimsPrincipal GetPrincipal(string token) { var handler = new JwtSecurityTokenHandler(); try { return handler.ValidateToken(token, new TokenValidationParameters { ValidateAudience = false, ValidateIssuer = false, ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(settings.SecurityKey)), ValidateLifetime = false }, out SecurityToken validatedToken); } catch (Exception) { return null; } } /// /// 校驗Token /// /// token /// public static bool CheckToken(string token) { var principal = GetPrincipal(token); if (principal is null) { return false; } return true; } /// /// 擷取Token中的載荷資料 /// /// token /// public static JwtPayload GetPayload(string token) { var jwtHandler = new JwtSecurityTokenHandler(); JwtSecurityToken securityToken = jwtHandler.ReadJwtToken(token); return new JwtPayload { UserId = securityToken.Id, UserName = securityToken.Payload[JwtRegisteredClaimNames.Sub]?.ToString(), RoleId = (securityToken.Payload[ClaimTypes.Role] ?? 0).ToString(), ExpTime = (securityToken.Payload[JwtRegisteredClaimNames.Exp] ?? 0).TimeStampToDate() }; } /// /// 擷取Token中的載荷資料 /// /// 泛型 /// token /// public static T GetPayload(string token) { var jwtHandler = new JwtSecurityTokenHandler(); JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(token); return JsonConvert.DeserializeObject(jwtToken.Payload.SerializeToJson()); } /// /// 判斷token是否過期 /// /// /// public static bool IsExp(string token) { return GetPrincipal(token)?.Claims.First(c => c.Type == JwtRegisteredClaimNames.Exp)?.Value?.TimeStampToDate() < DateTime.Now; //return GetPayload(token).ExpTime < DateTime.Now; } #region 從上下文請求流操作 /// /// 判斷是否為AJAX請求 /// /// /// public static bool IsAjaxRequest(HttpRequest req) { bool result = false; var xreq = req.Headers.ContainsKey("x-requested-with"); if (xreq) { result = req.Headers["x-requested-with"] == "XMLHttpRequest"; } return result; } /// /// 擷取Token /// /// 請求流 /// public static string GetToken(HttpRequest req) { string tokenHeader = req.Headers["Authorization"].ToString(); if (string.IsNullOrEmpty(tokenHeader)) throw new Exception("缺少token!"); string pattern = "^Bearer (.*?)$"; if (!Regex.IsMatch(tokenHeader, pattern)) throw new Exception("token格式不對!格式為:Bearer {token}"); string token = Regex.Match(tokenHeader, pattern).Groups[1]?.ToString(); if (string.IsNullOrEmpty(token)) throw new Exception("token不能為空!"); return token; } #endregion }}