using IdentityModel; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; using System; using System.Threading.Tasks; using System.Security.Claims; using System.IdentityModel.Tokens.Jwt; using System.Collections.Generic; using System.Text; namespace TEAMModelOS.SDK.Extension { public static class JwtAuthExtension { public static string CreateAuthToken(string issuer, string userID, string salt, string[] roles = null, string[] permissions = null, int expire = 1) { // 設定要加入到 JWT Token 中的聲明資訊(Claims) var claims = new List(); // 在 RFC 7519 規格中(Section#4),總共定義了 7 個預設的 Claims claims.Add(new Claim(JwtRegisteredClaimNames.Iss, issuer)); //發行者 claims.Add(new Claim(JwtRegisteredClaimNames.Sub, userID)); // 用戶ID claims.Add(new Claim(JwtRegisteredClaimNames.Exp, DateTimeOffset.UtcNow.AddHours(expire).ToUnixTimeSeconds().ToString())); // 到期的時間,必須為數字 // 擴充 "roles" 加入登入者的角色,角色類型 (USER、HABOOK) foreach (var role in roles) { claims.Add(new Claim("roles", role)); } // 擴充 "permissions" 加入登入者的權限請求 foreach (var role in permissions) { claims.Add(new Claim("permissions", role)); } // 建立一組對稱式加密的金鑰,主要用於 JWT 簽章之用 var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(salt)); // HmacSha256 有要求必須要大於 128 bits,所以 salt 不能太短,至少要 16 字元以上 // https://stackoverflow.com/questions/47279947/idx10603-the-algorithm-hs256-requires-the-securitykey-keysize-to-be-greater var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature); // 建立 SecurityTokenDescriptor var tokenDescriptor = new SecurityTokenDescriptor { Issuer = issuer, Subject = new ClaimsIdentity(claims), Expires = DateTime.Now.AddHours(expire), SigningCredentials = signingCredentials }; // 產出所需要的 JWT securityToken 物件,並取得序列化後的 Token 結果(字串格式) var tokenHandler = new JwtSecurityTokenHandler(); var securityToken = tokenHandler.CreateToken(tokenDescriptor); var serializeToken = tokenHandler.WriteToken(securityToken); return serializeToken; } public static bool ValidateAuthToken(string token, string salt) { try { var handler = new JwtSecurityTokenHandler(); var validationParameters = new TokenValidationParameters { RequireExpirationTime = true, ValidateIssuer = false, ValidateAudience = false, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(salt)), ValidateLifetime = false, //LifetimeValidator = LifetimeValidator, ClockSkew = TimeSpan.Zero }; ClaimsPrincipal principal = handler.ValidateToken(token, validationParameters, out SecurityToken securityToken); return true; } catch (Exception ex) { //Trace.WriteLine(ex.Message); return false; } } } }