JwtAuthExtension.cs 4.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. using IdentityModel;
  2. using Microsoft.AspNetCore.Authentication.JwtBearer;
  3. using Microsoft.AspNetCore.Authorization;
  4. using Microsoft.Extensions.Configuration;
  5. using Microsoft.Extensions.DependencyInjection;
  6. using Microsoft.IdentityModel.Tokens;
  7. using System;
  8. using System.Threading.Tasks;
  9. using System.Security.Claims;
  10. using System.IdentityModel.Tokens.Jwt;
  11. using System.Collections.Generic;
  12. using System.Text;
  13. namespace TEAMModelOS.SDK.Extension
  14. {
  15. public static class JwtAuthExtension
  16. {
  17. public static string CreateAuthToken(string issuer, string id,string name,string picture, string salt, string schoolID = "", string[] roles = null, string[] permissions = null, int expire = 1)
  18. {
  19. // 設定要加入到 JWT Token 中的聲明資訊(Claims)
  20. var claims = new List<Claim>();
  21. // 在 RFC 7519 規格中(Section#4),總共定義了 7 個預設的 Claims
  22. claims.Add(new Claim(JwtRegisteredClaimNames.Iss, issuer)); //發行者
  23. claims.Add(new Claim(JwtRegisteredClaimNames.Sub, id)); // 用戶ID
  24. claims.Add(new Claim("name", name)); // 用戶的顯示名稱
  25. claims.Add(new Claim("picture", picture)); // 用戶頭像
  26. claims.Add(new Claim(JwtRegisteredClaimNames.Azp, schoolID)); // 學校簡碼,如果有的話
  27. claims.Add(new Claim(JwtRegisteredClaimNames.Exp, DateTimeOffset.UtcNow.AddHours(expire).ToUnixTimeSeconds().ToString())); // 到期的時間,必須為數字
  28. // 擴充 "roles" 加入登入者的角色,角色類型 (USER、HABOOK)
  29. if (roles != null)
  30. {
  31. foreach (var role in roles)
  32. {
  33. claims.Add(new Claim("roles", role));
  34. }
  35. }
  36. // 擴充 "permissions" 加入登入者的權限請求
  37. if (permissions != null)
  38. {
  39. foreach (var role in permissions)
  40. {
  41. claims.Add(new Claim("permissions", role));
  42. }
  43. }
  44. // 建立一組對稱式加密的金鑰,主要用於 JWT 簽章之用
  45. var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(salt));
  46. // HmacSha256 有要求必須要大於 128 bits,所以 salt 不能太短,至少要 16 字元以上
  47. // https://stackoverflow.com/questions/47279947/idx10603-the-algorithm-hs256-requires-the-securitykey-keysize-to-be-greater
  48. var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
  49. // 建立 SecurityTokenDescriptor
  50. var tokenDescriptor = new SecurityTokenDescriptor
  51. {
  52. Issuer = issuer,
  53. Subject = new ClaimsIdentity(claims),
  54. Expires = DateTime.Now.AddHours(expire),
  55. SigningCredentials = signingCredentials
  56. };
  57. // 產出所需要的 JWT securityToken 物件,並取得序列化後的 Token 結果(字串格式)
  58. var tokenHandler = new JwtSecurityTokenHandler();
  59. var securityToken = tokenHandler.CreateToken(tokenDescriptor);
  60. var serializeToken = tokenHandler.WriteToken(securityToken);
  61. return serializeToken;
  62. }
  63. public static bool ValidateAuthToken(string token, string salt)
  64. {
  65. try
  66. {
  67. var handler = new JwtSecurityTokenHandler();
  68. var validationParameters = new TokenValidationParameters
  69. {
  70. RequireExpirationTime = true,
  71. ValidateIssuer = false,
  72. ValidateAudience = false,
  73. IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(salt)),
  74. ValidateLifetime = false,
  75. //LifetimeValidator = LifetimeValidator,
  76. ClockSkew = TimeSpan.Zero
  77. };
  78. ClaimsPrincipal principal = handler.ValidateToken(token, validationParameters, out SecurityToken securityToken);
  79. return true;
  80. }
  81. catch (Exception ex)
  82. {
  83. //Trace.WriteLine(ex.Message);
  84. return false;
  85. }
  86. }
  87. }
  88. }