最近在开发项目中,为了便于操作jwt,自己封装了一个jwthelper,发出来,供大家一起讨论。
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 }}