2022-11-14 13:36:02 +08:00
|
|
|
|
using Microsoft.Extensions.Configuration;
|
2022-10-14 16:08:54 +08:00
|
|
|
|
using Microsoft.Extensions.Options;
|
|
|
|
|
using Microsoft.IdentityModel.Tokens;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
|
|
|
using System.Security.Claims;
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
namespace FrontendWebApi.Jwt
|
|
|
|
|
{
|
|
|
|
|
public interface IJwtHelpers
|
|
|
|
|
{
|
|
|
|
|
TnToken GenerateToken(JwtLogin login);
|
|
|
|
|
}
|
|
|
|
|
public class JwtHelpers: IJwtHelpers
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
private readonly IConfiguration _configuration;
|
|
|
|
|
public JwtHelpers(IConfiguration configuration)
|
|
|
|
|
{
|
|
|
|
|
_configuration = configuration;
|
|
|
|
|
}
|
|
|
|
|
public TnToken GenerateToken(JwtLogin login)
|
|
|
|
|
{
|
|
|
|
|
var issuer = _configuration.GetValue<string>("JwtSettings:Issuer");
|
|
|
|
|
var signKey = _configuration.GetValue<string>("JwtSettings:SignKey");
|
|
|
|
|
var lifeseconds = _configuration.GetValue<int>("JwtSettings:JwtLifeSeconds");
|
|
|
|
|
// 設定要加入到 JWT Token 中的聲明資訊(Claims)
|
|
|
|
|
var claims = new List<Claim>();
|
|
|
|
|
|
|
|
|
|
// 在 RFC 7519 規格中(Section#4),總共定義了 7 個預設的 Claims,我們應該只用的到兩種!
|
|
|
|
|
claims.Add(new Claim(JwtRegisteredClaimNames.Iss, issuer));
|
|
|
|
|
//claims.Add(new Claim(JwtRegisteredClaimNames.NameId, login.CustomerNo.ToString()));
|
|
|
|
|
//claims.Add(new Claim(JwtRegisteredClaimNames.Sub, login.Username)); // User.Identity.Name
|
|
|
|
|
//claims.Add(new Claim(JwtRegisteredClaimNames.Aud, "The Audience"));
|
2022-11-04 09:41:50 +08:00
|
|
|
|
claims.Add(new Claim(JwtRegisteredClaimNames.Exp, DateTimeOffset.UtcNow.AddSeconds(lifeseconds).ToUnixTimeSeconds().ToString()));
|
|
|
|
|
claims.Add(new Claim(JwtRegisteredClaimNames.Nbf, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())); // 必須為數字
|
2022-10-14 16:08:54 +08:00
|
|
|
|
//claims.Add(new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())); // 必須為數字
|
|
|
|
|
//claims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())); // JWT ID
|
|
|
|
|
|
|
|
|
|
// 網路上常看到的這個 NameId 設定是多餘的
|
|
|
|
|
//claims.Add(new Claim(JwtRegisteredClaimNames.NameId, userName));
|
|
|
|
|
|
|
|
|
|
// 這個 Claim 也以直接被 JwtRegisteredClaimNames.Sub 取代,所以也是多餘的
|
|
|
|
|
//claims.Add(new Claim(ClaimTypes.Name, userName));
|
|
|
|
|
|
|
|
|
|
// 你可以自行擴充 "roles" 加入登入者該有的角色
|
|
|
|
|
//claims.Add(new Claim("roles", "Users"));
|
|
|
|
|
//claims.Add(new Claim("groupid", login.AreaCode));
|
|
|
|
|
claims.Add(new Claim("userinfo_guid", login.userinfo_guid));
|
|
|
|
|
claims.Add(new Claim("account", login.account));
|
|
|
|
|
claims.Add(new Claim("full_name", login.full_name));
|
|
|
|
|
claims.Add(new Claim("email", login.email));
|
|
|
|
|
var userClaimsIdentity = new ClaimsIdentity(claims);
|
|
|
|
|
|
|
|
|
|
// 建立一組對稱式加密的金鑰,主要用於 JWT 簽章之用
|
|
|
|
|
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(signKey));
|
|
|
|
|
|
|
|
|
|
// HmacSha256 有要求必須要大於 128 bits,所以 key 不能太短,至少要 16 字元以上
|
|
|
|
|
// https://stackoverflow.com/questions/47279947/idx10603-the-algorithm-hs256-requires-the-securitykey-keysize-to-be-greater
|
|
|
|
|
var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
|
|
|
|
|
|
2023-09-20 17:32:03 +08:00
|
|
|
|
var now = DateTime.UtcNow;
|
|
|
|
|
var expires = DateTime.UtcNow.AddSeconds(lifeseconds);
|
2022-10-14 16:08:54 +08:00
|
|
|
|
|
|
|
|
|
// 產出所需要的 JWT securityToken 物件,並取得序列化後的 Token 結果(字串格式)
|
|
|
|
|
var tokenHandler = new JwtSecurityTokenHandler();
|
|
|
|
|
|
|
|
|
|
var jst = new JwtSecurityToken(
|
2022-11-04 09:41:50 +08:00
|
|
|
|
issuer: issuer,//Token釋出者
|
|
|
|
|
//audience: _options.Value.Audience,//Token接受者
|
|
|
|
|
claims: claims,//攜帶的負載
|
|
|
|
|
notBefore: now,//當前時間token生成時間
|
|
|
|
|
expires: expires,//過期時間
|
|
|
|
|
signingCredentials: signingCredentials
|
|
|
|
|
);
|
|
|
|
|
//var jst = new SecurityTokenDescriptor
|
|
|
|
|
//{
|
|
|
|
|
// Issuer = issuer,//Token釋出者
|
|
|
|
|
// //Claims = claims,//攜帶的負載
|
|
|
|
|
// //audience: _options.Value.Audience,//Token接受者
|
|
|
|
|
// NotBefore = now,//當前時間token生成時間
|
|
|
|
|
// Expires = expires,//過期時間
|
|
|
|
|
// SigningCredentials = signingCredentials,
|
|
|
|
|
// Subject = userClaimsIdentity
|
|
|
|
|
//};
|
|
|
|
|
|
2022-10-14 16:08:54 +08:00
|
|
|
|
var serializeToken = tokenHandler.WriteToken(jst);
|
|
|
|
|
|
|
|
|
|
var data = new TnToken();
|
|
|
|
|
data.token = serializeToken;
|
|
|
|
|
data.type = "bearer";
|
|
|
|
|
data.expires= lifeseconds;
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|