JWT學習筆記Part1(產製Token)

跨伺服器交換資料,用JWT就對了,安全可靠。

認識JWT,請參考以下文章:

有了基本的認識後,HS開頭的簽章方式是用secret(密語),把secret給其他伺服器就能驗證簽章,本案例使用asp.net,請參考以下Code(要用NuGet下載System.JdentityModel.Tokens.Jwt)。

// header            
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("db3OIsj+BXE9NZDy0t8W3TcNekrF+2d/1sFnWG4HnV8TZY30iTOdtVWJG8abWvB1GlOgJuQZdcF2Luqm/hccMw=="));
var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var header = new JwtHeader(signingCredentials);

// payload
IReadOnlyDictionary<string, string> payloadContents = new Dictionary<string, string>
{
    { "username","Mika" },
    { "iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds() },
    { "exp", DateTimeOffset.UtcNow.AddMinutes(5).ToUnixTimeSeconds()},
};

var payloadClaims = payloadContents.Select(c => new Claim(c.Key, c.Value));
var payload = new JwtPayload(payloadClaims);

// signature
var securityToken = new JwtSecurityToken(header, payload);

// return
var tokenHandler = new JwtSecurityTokenHandler();
return tokenHandler.WriteToken(securityToken);

但是secret難保不會洩漏,所以更安全的方式就是用非對稱式金鑰(RS開頭),建議使用NuGet下載jose-jwt與BouncyCastle,會簡單很多,首先要製作一對非對稱式金鑰,公鑰可以任意給人,但私鑰只能安全的放在Server上,使用指令如下。

openssl genrsa -out privateKey.pem 2048
openssl rsa -in privateKey.pem -pubout -out publicKey.pem

如果找不到Openssl指令,可以自己上網抓並安裝,但是其實一般有使用到Git,就已經安裝在電腦中了,Windows可以在以下位置找到 C:\Program Files\Git\usr\bin\

接著是Code的部分,可以參考以下,如果要驗證,產生的token對不對可以至官網驗證 https://jwt.io/

public string Test()
{
    var claims = new List<Claim>();
    claims.Add(new Claim("username", "Mika"));
    claims.Add(new Claim("iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString()));
    claims.Add(new Claim("exp", DateTimeOffset.UtcNow.AddMinutes(5).ToUnixTimeSeconds().ToString()));
    var token = CreateToken(claims);

    return token;
}

public static string CreateToken(List<Claim> claims)
{
    string privateRsaKey = File.ReadAllText(Path.Combine(HttpContext.Current.Request.PhysicalApplicationPath, @"App_Data\JwtKey\private_Key.pem"));
    RSAParameters rsaParams;
    using (var tr = new StringReader(privateRsaKey))
    {
        var pemReader = new PemReader(tr);
        var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
        if (keyPair == null)
        {
            throw new Exception("Could not read RSA private key");
        }
        var privateRsaParams = keyPair.Private as RsaPrivateCrtKeyParameters;
        rsaParams = DotNetUtilities.ToRSAParameters(privateRsaParams);
    }
    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
    {
        rsa.ImportParameters(rsaParams);
        Dictionary<string, object> payload = claims.ToDictionary(k => k.Type, v => (object)v.Value);
        return Jose.JWT.Encode(payload, rsa, Jose.JwsAlgorithm.RS256);
    }
}

參考網址:

發佈留言