如何使用System.IdentityModel.Tokens.Jwt使用GoogleOAuth2兼容算法RSASHA-256生成JWT?我正在尝试使用System.IdentityModel.Tokens.Jwt创建一个JWT以使用服务帐户进行授权,如Google文档中所述。我有以下代码:byte[]key=Convert.FromBase64String("...");varcertificate=newX509Certificate2(key,"notasecret");DateTime现在=DateTime.UtcNow;TimeSpanspan=now-UnixEpoch;Claim[]claims={newClaim("iss","email@developer.gserviceaccount.com"),newClaim("scope","https://www.googleapis.com/auth/plus.me"),新声明(“aud”,“https://accounts.google.com/o/oauth2/token”),新声明(“iat”,span.TotalSeconds.ToString()),新声明(“exp”,跨度.Add(TimeSpan.FromHours(1)).TotalSeconds.ToString())};JwtSecurityTokenHandlerhandler=newJwtSecurityTokenHandler();vardescriptor=newSecurityTokenDescriptor{SigningCredentials=newSigningCredentials(newInMemorySymmetricSecurityKey(key),"http://www.w3.org/2001/04/xmldsig-more#hmac-sha256","http://www.w3.org/2001/04/xmlenc#sha256"),Subject=newClaimsIdentity(claims)};JwtSecurityTokenjwtSecurityToken=(JwtSecurityToken)handler.CreateToken(描述符);字符串json=handler.WriteToken(jwtSecurityToken);其中输出:{"typ":"JWT","alg":"HS256"}虽然谷歌明确声明它支持SHA-256:服务帐户依赖于RSASHA-256算法和JWT令牌格式根据wtSecurityTokenHandler。InboundAlgorithmMap:RS256=>http://www.w3.org/2001/04/xmldsig-more#rsa-sha256HS256=>http://www.w3.org/2001/04/xmldsig-more#hmac-sha256所以当我更改代码时:newSigningCredentials(newInMemorySymmetricSecurityKey(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')抛出异常。SymmetricSecurityKey:'System.IdentityModel.Tokens.InMemorySymmetricSecurityKey'SignatureAlgorithm:'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',检查以确保支持SignatureAlgorithm。这是否意味着微软不支持谷歌独家支持的算法?私有静态异步任务GetAuthorizationToken(GoogleAuthOptionsauthOptions){stringjwt=CreateJwt(authOptions);vardic=newDictionary{{"grant_type","urn:ietf:params:oauth:grant-type:jwt-bearer"},{"assertion",jwt}};varcontent=newFormUrlEncodedContent(dic);varhttpClient=newHttpClient{BaseAddress=newUri("https://accounts.google.com")};varresponse=awaithttpClient.PostAsync("/o/oauth2/token",content);响应.EnsureSuccessStatusCode();dynamicdyn=awaitresponse.Content.ReadAsAsync();返回dyn.access_token;}privatestaticreadonlyDateTimeUnixEpoch=newDateTime(1970,1,1,0,0,0,0,DateTimeKind.Utc);privatestaticstringCreateJwt(GoogleAuthOptionsauthOptions){varcertificate=newX509Certificate2(Convert.FromBase64String(authOptions.CertificateKey),authOptions.CertificateSecret);DateTime现在=DateTime.UtcNow;varclaimset=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)};//headervarheader=new{typ="JWT",alg="RS256"};//编码头varheaderSerialized=JsonConvert.SerializeObject(header);varheaderBytes=Encoding.UTF8.GetBytes(headerSerialized);varheaderEncoded=TextEncodings.Base64Url.Encode(headerBytes);//编码的声明集varclaimsetSerialized=JsonConvert.SerializeObject(claimset);varclaimsetBytes=Encoding.UTF8.GetBytes(claimsetSerialized);varclaimsetEncoded=TextEncodings.Base64Url.Encode(claimsetBytes);//输入varinput=String.Join(".",headerEncoded,claimsetEncoded);varinputBytes=Encoding.UTF8.GetBytes(输入);//signiturevarrsa=(RSACryptoServiceProvider)certificate.PrivateKey;varcspParam=newCspParameters{KeyContainerName=rsa.CspKeyContainerInfo.KeyContainerName,KeyNumber=rsa.CspKeyContainerInfo.KeyNumber==KeyNumber.Exchange?1:2};varcryptoServiceProvider=newRSACryptoServiceProvider(cspParam){PersistKeyInCsp=false};varsignatureBytes=cryptoServiceProvider.SignData(inputBytes,"SHA256");(签名字节);//jwtreturnString.Join(".",headerEncoded,claimsetEncoded,signatureEncoded);自问这个问题以来已经有一段时间了,但我认为对于未来的人来说,使用它很容易在几行代码中使用.NETGoogleAuthAPI(其核心版本)获得相同的结果在此处可用:Google.Apis.Auth使用System.Security.Cryptography.X509Certificates;使用System.Threading;使用System.Threading.Tasks;使用Google.Apis.Auth.OAuth2;命名空间GoogleTest{publicclassGoogleOAuth2{//////我们请求的授权范围///privatereadonlystring_defaultScope;//////服务帐户的形式为nnnnnnn@developer.gserviceaccount.com///privatereadonlystring_serviceAccount;//////设置这是您私人服务帐户的完整路径e密钥文件。///私有只读字符串_certificateFile;publicGoogleOAuth2(stringdefaultScope,stringserviceAccount,stringcertificateFile){_defaultScope=defaultScope;_serviceAccount=服务帐户;_certificateFile=证书文件;}//////Google令牌服务器返回的访问令牌///publicstringAccessToken{get;放;}publicasyncTaskRequestAccessTokenAsync(){varcertificate=newX509Certificate2(_certificateFile,"notasecret",X509KeyStorageFlags.Exportable);varserviceAccountInCredential=newServiceAccountCrederial(newServiceAccountCredential){Scopes=new[]{_defaultScope}}.FromCertificate(证书));varstatus=awaitserviceAccountCredential.RequestAccessTokenAsync(CancellationToken.None);如果(状态)AccessToken=serviceAccountCredential.Token.AccessToken;返回状态;accesstoken,你只需要调用RequestAccessTokenAsync方法,如果结果成功,你就可以在AccessToken属性中获取token请注意,此实现假定您已在开发人员控制台中将私钥导出为.P12文件。希望这个答案有所帮助。我不得不稍微修改@abatishchev的代码。否则部署到非开发环境时生成证书会出现问题。问题是双重的。如果证书未标记为可导出,则会抛出异常,例如“keysetdoesnotexist”。它只发生在服务器上,而不是本地,所以我怀疑Windows的服务器版本限制更多。此外,它还会引发有关计算机信任问题的加密异常,因为证书是在用户密钥集中创建的。我们的应用程序池设置为不在高级选项中导入用户配置文件,您可以这样做。但由于与其他应用程序的兼容性问题,它对我们不起作用。在机器的密钥集中设置要创建的证书可以缓解这个问题。2个更改的部分标有注释。以上就是C#学习教程:HowtouseSystem.IdentityModel.Tokens.JwttogenerateJWTusingGoogleOAuth2compatiblealgorithmRSASHA-256?分享的所有内容,如果对你有用,需要了解更多C#学习教程,希望你多多关注—vardic=newDictionary{{"grant_type","urn:ietf:params:oauth:grant-type:jwt-bearer"},{"assertion",jwt}};varcontent=newFormUrlEncodedContent(dic);varhttpClient=newHttpClient{BaseAddress=newUri("https://accounts.google.com")};varresponse=awaithttpClient.PostAsync("/o/oauth2/token",content);响应.EnsureSuccessStatusCode();dynamicdyn=awaitresponse.Content.ReadAsAsync();返回dyn.access_token;}privatestaticreadonlyDateTimeUnixEpoch=newDateTime(1970,1,1,0,0,0,0,DateTimeKind.Utc);privatestaticstringCreateJwt(GoogleAuthOptionsauthOptions){/*已更改*/constX509KeyStorageFlagscertificateFlags=X509KeyStorageFlags.MachineKeySet|X509KeyStorageFlags.PersistKeySet|X509KeyStorageFlags.Exportable;varcertificate=newX509Certificate2(Convert.FromBase64String(authOptions.CertificateKey),authOptions.CertificateSecret,certificateFlags);/*更改结束*/DateTimenow=DateTime.UtcNow;varclaimset=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)};//headervarheader=new{typ="JWT",alg="RS256"};//编码头varheaderSerialized=JsonConvert.SerializeObject(header);varheaderBytes=Encoding.UTF8.GetBytes(headerSerialized);varheaderEncoded=TextEncodings.Base64Url.Encode(headerBytes);//编码的声明集varclaimsetSerialized=JsonConvert.SerializeObject(claimset);varclaimsetBytes=Encoding.UTF8.GetBytes(claimsetSerialized);varclaimsetEncoded=TextEncodings.Base64Url.Encode(claimsetBytes);//输入varinput=String.Join(".",headerEncoded,claimsetEncoded);varinputBytes=Encoding.UTF8.GetBytes(输入);//签名varrsa=(RSACryptoServiceProvider)certificate.PrivateKey;varcspParam=newCspParameters{KeyContainerName=rsa.CspKeyContainerInfo.KeyContainerName,/*已更改*/KeyNumber=(int)KeyNumber.Exchange,Flags=CspProviderFlags.UseMachineKeyofstore/*/};varcryptoServiceProvider=newRSACryptoServiceProvider(cspParam){PersistKeyInCsp=false};varsignatureBytes=cryptoServiceProvider.SignData(inputBytes,"SHA256");(".",headerEncoded,claimsetEncoded,signatureEncoded);}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如有转载请注明出处:
