问题
The documentation is at Using OAuth 2.0 for Server to Server Applications You will notice in the documentation the disclaimer "don't do this but use the libraries". Unfortunately, there does NOT appear to be .Net Core libraries and I have suggested to the Smarthome program managers that support for .Net Core should be the same as provided for Java, node.js and Python.
However, I'm hunkered down, socially distanced and have some time available so I gave it a shot. There are a lot of moving parts here but to start I downloaded a p12 file instead of a JSON file (as indicated in the documentation) from the Google Console for the account.
The code:
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace MakeJWTTest
{
class Program
{
static void Main(string[] args)
{
string token = MakeJwt();
Console.WriteLine();
Console.WriteLine("The Final JWT: " + token );
}
public static string MakeJwt()
{
string jwt = string.Empty;
string iss = "XXXXXXXXXXXXXXX-v2.iam.gserviceaccount.com";
string scope = "https://www.googleapis.com/auth/homegraph";
string aud = "https://oauth2.googleapis.com/token";
string exp = EpochExpiration();
string iat = EpochCurrentTime();
string jwtHeader = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
Console.WriteLine("iss: " + iss);
Console.WriteLine("scope: " + scope);
Console.WriteLine("aud: " + aud);
Console.WriteLine("exp: " + exp);
Console.WriteLine("iat: " + iat);
Console.WriteLine("JWT Header: " + jwtHeader);
string claim = "{\"iss\": \"" + iss + "\",\"scope\": \"" + scope + "\",\"aud\": \"" + aud + "\",\"exp\": " +
exp + ",\"iat\": " + iat + "}";
var encodedHeader = Base64UrlEncoder.Encode(jwtHeader);
Console.WriteLine("Encoded JWT Header: " + encodedHeader);
var encodedClaim = Base64UrlEncoder.Encode(claim);
string claimSet = encodedHeader + "." + encodedClaim;
string sig = Sign(claimSet);
jwt = claimSet + '.' + sig;
return jwt;
}
public static string EpochExpiration()
{
DateTime epoch = DateTime.UnixEpoch;
DateTime now = DateTime.UtcNow;
DateTime expiration = now.AddMinutes(60);
TimeSpan secondsSinceEpoch = expiration.Subtract(epoch);
return secondsSinceEpoch.TotalSeconds.ToString().Substring(0, 10);
}
public static string EpochCurrentTime()
{
DateTime epoch = DateTime.UnixEpoch;
DateTime now = DateTime.UtcNow;
TimeSpan secondsSinceEpoch = now.Subtract(epoch);
return secondsSinceEpoch.TotalSeconds.ToString().Substring(0, 10);
}
public static string Sign( string toSHA256)
{
try
{
byte[] data = Encoding.ASCII.GetBytes(toSHA256);
var certificate = new X509Certificate2(@"XXXXXXXXXXXXXXX-v2-6790af22aa27.p12", "notasecret", X509KeyStorageFlags.Exportable);
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
// byte[] key = certificate.PrivateKey.ExportPkcs8PrivateKey();
key.FromXmlString(certificate.PrivateKey.ToXmlString(true));
//Sign the data
byte[] sig = key.SignData(data, CryptoConfig.MapNameToOID("SHA256"));
return Base64UrlEncoder.Encode(sig);
}
catch { Exception e; return null; }
}
}
}
Run this program and I get:
scope: https://www.googleapis.com/auth/homegraph
aud: https://oauth2.googleapis.com/token
exp: 1586193162
iat: 1586189562
JWT Header: {"alg":"RS256","typ":"JWT"}
Encoded JWT Header: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
The Final JWT: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiAibGltaXRlZG1vYmlsaXR5djJAbGltaXRlZC1tb2JpbGl0eS1zb2x1dGlvbnMtdjIuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iICJzY29wZSI6ICJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL2hvbWVncmFwaCJhdWQiOiAiaHR0cHM6Ly9vYXV0aDIuZ29vZ2xlYXBpcy5jb20vdG9rZW4iZXhwIjogIjE1ODYxOTMxNjIiaWF0IjogMTU4NjE4OTU2Mg.ZOX93iUhirtH2tf95XzLYrGIbTK8kABipfVa6DnD-sAe3WcRfLmLVIAybtHTHxC8frCuZtCeS4XMT-EC69kLy-ks5BWFTnaRwm0TfIeNzIVrGfJUVRchvaJLFM9-wX6svVa4fGHMp8pKttO22BI3sIEisxXx2tw6Ge_8QRZXjSCXD0rg5P-0S-pnd8omkgPv_PhhALqcwd9RTUpcAqcMDoyP7ZxpBSMt1EwySixctKz2y4sRCGC8xaxp5E5VnH3liz3xTNMY5QRNX-tMxVIunh0Qp9v7bkuuvnhrwbcjRPq9qTKlhfIQBmZvaA5-9hzJZOiWWHmCunMec1pZp0bAgQ
Press any key to close this window . . .
I then run this from Powershell using curl:
.\curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.RZVpzWygMLuL-n3GwjW1_yhQhrqDacyvaXkuf8HcJl8EtXYjGjMaW5oiM5cgAaIorrqgYlp4DPF_GuncFqg9uDZrx7pMmCZ_yHfxhSCXru3gbXrZvAIicNQZMFxrEEn4REVuq7DjkTMyCMGCY1dpMa8aWfTQFt3Eh7smLchaZsU' https://oauth2.googleapis.com/token
Which returns:
{"error":"invalid_grant","error_description":"Invalid grant: account not found"}
Could be a bunch of things wrong here. Any thoughts welcomed.
回答1:
There were two errors in the code:
- The JSON string
claim = "{\"iss\": \"" + iss + "\",\"scope\": \"" + scope +
"\",\"aud\": \"" + aud + "\",\"exp\": " +
exp + ",\"iat\": " + iat + "}";
- The DateTime needs to be UTC
And now it works.
来源:https://stackoverflow.com/questions/61068471/googlesmarthome-jwt-creation