如何使用 System.IdentityModel.Tokens.Jwt 生成具有 Google OAuth2 兼容算法 RSA SHA-256 的 JWT? [英] How to produce JWT with Google OAuth2 compatible algorithm RSA SHA-256 using System.IdentityModel.Tokens.Jwt?

查看:37
本文介绍了如何使用 System.IdentityModel.Tokens.Jwt 生成具有 Google OAuth2 兼容算法 RSA SHA-256 的 JWT?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个 JWT 以使用 Google 文档中所述的服务帐户进行授权,使用 System.IdentityModel.Tokens.Jwt.我有以下代码:

I'm trying to create a JWT to authorize with a service account as described in Google documentation using System.IdentityModel.Tokens.Jwt. I have the following code:

byte[] key = Convert.FromBase64String("...");
var certificate = new X509Certificate2(key, "notasecret");

DateTime now = DateTime.UtcNow;
TimeSpan span = now - UnixEpoch;
Claim[] claims =
{
    new Claim("iss", "email@developer.gserviceaccount.com"),
    new Claim("scope", "https://www.googleapis.com/auth/plus.me"),
    new Claim("aud", "https://accounts.google.com/o/oauth2/token"),
    new Claim("iat", span.TotalSeconds.ToString()),
    new Claim("exp", span.Add(TimeSpan.FromHours(1)).TotalSeconds.ToString())
};

JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
var descriptor = new SecurityTokenDescriptor
{
    SigningCredentials = new SigningCredentials(
        new InMemorySymmetricSecurityKey(key),
        "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
        "http://www.w3.org/2001/04/xmlenc#sha256"),
    Subject = new ClaimsIdentity(claims)
};

JwtSecurityToken jwtSecurityToken = (JwtSecurityToken)handler.CreateToken(descriptor);
string json = handler.WriteToken(jwtSecurityToken);

哪个输出:

{ "typ" : "JWT" , "alg" : "HS256" }

虽然 Google 明确声明它支持 SHA-256:

While Google explicitly states it supports SHA-256:

服务帐号依赖于 RSA SHA-256 算法和 JWT 令牌格式

Service accounts rely on the RSA SHA-256 algorithm and the JWT token format

根据 wtSecurityTokenHandler.InboundAlgorithmMap:

RS256 => http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
HS256 => http://www.w3.org/2001/04/xmldsig-more#hmac-sha256 

所以当我更改代码时:

new SigningCredentials(
    new InMemorySymmetricSecurityKey(key),
        "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
        "http://www.w3.org/2001/04/xmlenc#sha256");

我遇到了一个异常:

System.InvalidOperationException: IDX10632: SymmetricSecurityKey.GetKeyedHashAlgorithm( 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256' ) threw an exception.
SymmetricSecurityKey: 'System.IdentityModel.Tokens.InMemorySymmetricSecurityKey'
SignatureAlgorithm: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', check to make sure the SignatureAlgorithm is supported.

这是否意味着微软不支持谷歌独家支持的算法?

Does it mean Microsoft doesn't support the algorithm Google supports exclusively?

推荐答案

private static async Task<string> GetAuthorizationToken(GoogleAuthOptions authOptions)
{
    string jwt = CreateJwt(authOptions);

    var dic = new Dictionary<string, string>
    {
        { "grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer" },
        { "assertion", jwt }
    };
    var content = new FormUrlEncodedContent(dic);

    var httpClient = new HttpClient { BaseAddress = new Uri("https://accounts.google.com") };
    var response = await httpClient.PostAsync("/o/oauth2/token", content);
    response.EnsureSuccessStatusCode();

    dynamic dyn = await response.Content.ReadAsAsync<dynamic>();
    return dyn.access_token;
}

private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);

private static string CreateJwt(GoogleAuthOptions authOptions)
{
    var certificate = new X509Certificate2(Convert.FromBase64String(authOptions.CertificateKey), authOptions.CertificateSecret);

    DateTime now = DateTime.UtcNow;
    var claimset = new
    {
        iss = authOptions.Issuer,
        scope = "https://www.googleapis.com/auth/plus.me",
        aud = authOptions.Audience,
        iat = ((int)now.Subtract(UnixEpoch).TotalSeconds).ToString(CultureInfo.InvariantCulture),
        exp = ((int)now.AddMinutes(55).Subtract(UnixEpoch).TotalSeconds).ToString(CultureInfo.InvariantCulture)
    };

    // header
    var header = new { typ = "JWT", alg = "RS256" };

    // encoded header
    var headerSerialized = JsonConvert.SerializeObject(header);
    var headerBytes = Encoding.UTF8.GetBytes(headerSerialized);
    var headerEncoded = TextEncodings.Base64Url.Encode(headerBytes);

    // encoded claimset
    var claimsetSerialized = JsonConvert.SerializeObject(claimset);
    var claimsetBytes = Encoding.UTF8.GetBytes(claimsetSerialized);
    var claimsetEncoded = TextEncodings.Base64Url.Encode(claimsetBytes);

    // input
    var input = String.Join(".", headerEncoded, claimsetEncoded);
    var inputBytes = Encoding.UTF8.GetBytes(input);

    // signiture
    var rsa = (RSACryptoServiceProvider)certificate.PrivateKey;
    var cspParam = new CspParameters
    {
        KeyContainerName = rsa.CspKeyContainerInfo.KeyContainerName,
        KeyNumber = rsa.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2
    };
    var cryptoServiceProvider = new RSACryptoServiceProvider(cspParam) { PersistKeyInCsp = false };
    var signatureBytes = cryptoServiceProvider.SignData(inputBytes, "SHA256");
    var signatureEncoded = TextEncodings.Base64Url.Encode(signatureBytes);

    // jwt
    return String.Join(".", headerEncoded, claimsetEncoded, signatureEncoded);
}

这篇关于如何使用 System.IdentityModel.Tokens.Jwt 生成具有 Google OAuth2 兼容算法 RSA SHA-256 的 JWT?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆