如何使用System.IdentityModel.Tokens.Jwt生产JWT与谷歌的OAuth2兼容RSA算法SHA-256? [英] How to produce JWT with Google OAuth2 compatible algorithm RSA SHA-256 using System.IdentityModel.Tokens.Jwt?
问题描述
我想作为使用谷歌文档中描述来创建一个JWT与服务帐户授权< A HREF =https://www.nuget.org/packages/System.IdentityModel.Tokens.Jwt/> System.IdentityModel.Tokens.Jwt 。我有以下代码:
字节[]键= Convert.FromBase64String(...);
无功证书=新X509Certificate2(关键,notasecret);
现在的DateTime = DateTime.UtcNow;
时间跨度跨度=现在 - UnixEpoch;
索赔[] =索赔
{
新的索赔(国际空间站,email@developer.gserviceaccount.com),
新的索赔(范围,请https: //www.googleapis.com/auth/plus.me),
新的索赔(澳元,https://accounts.google.com/o/oauth2/token),
新的索赔(IAT,span.TotalSeconds.ToString()),
新的索赔(EXP,span.Add(TimeSpan.FromHours(1))。TotalSeconds.ToString())
} ;
JwtSecurityTokenHandler处理程序=新JwtSecurityTokenHandler();
变种描述符=新SecurityTokenDescriptor
{
SigningCredentials =新SigningCredentials(
新InMemorySymmetricSecurityKey(键),
http://www.w3.org/2001/ 04 / XMLDSIG,更#HMAC-SHA256,
http://www.w3.org/2001/04/xmlenc#sha256),
=主题新ClaimsIdentity(索赔)
};
JwtSecurityToken jwtSecurityToken =(JwtSecurityToken)handler.CreateToken(描述);
JSON字符串= handler.WriteToken(jwtSecurityToken);
它输出:
{典型:智威汤逊,ALG:HS256}
尽管谷歌明确指出,它支持SHA-256:
服务帐户依靠在 RSA SHA-256 算法和JWT令牌格式
块引用>
据的 wtSecurityTokenHandler.InboundAlgorithmMap :
RS256 => http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
HS256 => http://www.w3.org/2001/04/xmldsig-more#hmac-sha256
所以,当我改变我的代码:
新SigningCredentials(
新InMemorySymmetricSecurityKey(键),
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')引发了异常。
SymmetricSecurityKey:System.IdentityModel.Tokens.InMemorySymmetricSecurityKey'
SignatureAlgorithm:http://www.w3.org/2001/04/xmldsig-more#rsa-sha256,检查以确保SignatureAlgorithm被支持。
这是否意味着微软不支持谷歌的算法支持独家?
解决方案私有静态异步任务<串GT; GetAuthorizationToken(GoogleAuthOptions authOptions)
{
字符串JWT = CreateJwt(authOptions);
变种DIC =新词典<字符串,字符串>
{
{grant_type,金塔:IETF:params:一个OAuth的:授型:智威汤逊的旗手},
{断言,智威汤逊}
};
变种内容=新FormUrlEncodedContent(DIC);
变种的HttpClient =新的HttpClient {BaseAddress =新的URI(https://accounts.google.com)};
VAR响应=等待httpClient.PostAsync(/ O /的oauth2 /令牌,内容);
response.EnsureSuccessStatusCode();
动态DYN =等待response.Content.ReadAsAsync<动态>();
返回dyn.access_token;
}
私人静态只读的DateTime UnixEpoch =新日期时间(1970年,1,1,0,0,0,0,DateTimeKind.Utc);
私人静态字符串CreateJwt(GoogleAuthOptions authOptions)
{
无功证书=新X509Certificate2(Convert.FromBase64String(authOptions.CertificateKey),authOptions.CertificateSecret);
现在的DateTime = DateTime.UtcNow;
变种claimset =新的
{
ISS = authOptions.Issuer,
范围=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)
};
//头
变种头= {新典型值=智威汤逊,ALG =RS256};
//编码首
VAR headerSerialized = JsonConvert.SerializeObject(头);
VAR headerBytes = Encoding.UTF8.GetBytes(headerSerialized);
VAR headerEncoded = TextEncodings.Base64Url.Encode(headerBytes);
//编码claimset
VAR claimsetSerialized = JsonConvert.SerializeObject(claimset);
VAR claimsetBytes = Encoding.UTF8.GetBytes(claimsetSerialized);
VAR claimsetEncoded = TextEncodings.Base64Url.Encode(claimsetBytes);
//输入
VAR输入=的string.join(,headerEncoded,claimsetEncoded。);
VAR inputBytes = Encoding.UTF8.GetBytes(输入);
// signiture
VAR RSA =(的RSACryptoServiceProvider)certificate.PrivateKey;
变种cspParam =新CspParameters
{
KeyContainerName = rsa.CspKeyContainerInfo.KeyContainerName,
KeyNumber = rsa.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange? 1:2
};
变种cryptoServiceProvider =新的RSACryptoServiceProvider(cspParam){PersistKeyInCsp = FALSE};
VAR signatureBytes = cryptoServiceProvider.SignData(inputBytesSHA256);
VAR signatureEncoded = TextEncodings.Base64Url.Encode(signatureBytes);
//智威汤逊
返回的string.join(,headerEncoded,claimsetEncoded,signatureEncoded。);
}
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);
which outputs:
{ "typ" : "JWT" , "alg" : "HS256" }
While Google explicitly states it supports SHA-256:
Service accounts rely on the RSA SHA-256 algorithm and the JWT token format
According to wtSecurityTokenHandler.InboundAlgorithmMap:
RS256 => http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 HS256 => http://www.w3.org/2001/04/xmldsig-more#hmac-sha256
So when I change my code:
new SigningCredentials( new InMemorySymmetricSecurityKey(key), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", "http://www.w3.org/2001/04/xmlenc#sha256");
I'm getting an exception:
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生产JWT与谷歌的OAuth2兼容RSA算法SHA-256?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!