Freebase oAuth2错误请求(400).Net

Freebase oAuth2错误请求(400).Net,.net,oauth-2.0,freebase,bad-request,.net,Oauth 2.0,Freebase,Bad Request,我用英语读了教程 并尝试使用他们的示例,但不断收到400个错误请求。 这是我的代码: ClaimSet cs = new ClaimSet() { aud = "https://www.googleapis.com/oauth2/v3/token", iss = "1070248278615-hoq0meaunarl9hj8t9klg4gqkohlme9u@developer.gserviceaccount.com",

我用英语读了教程

并尝试使用他们的示例,但不断收到400个错误请求。 这是我的代码:

 ClaimSet cs = new ClaimSet()
        {
            aud = "https://www.googleapis.com/oauth2/v3/token",
            iss = "1070248278615-hoq0meaunarl9hj8t9klg4gqkohlme9u@developer.gserviceaccount.com",
            exp = GetTime(DateTime.UtcNow.AddHours(1)).ToString(),
            iat = GetTime(DateTime.UtcNow).ToString(),
            scope = "https://www.googleapis.com/auth/freebase"
        };

        //get the signed JWT
        var signedJwt = JsonWebToken.Encode(cs);           


public static string Encode(object payload, JwtHashAlgorithm algorithm = JwtHashAlgorithm.RS256)
        {
            return Encode(payload, Encoding.UTF8.GetBytes(PrivateKey), algorithm);
        }

    public static string Encode(object payload, byte[] keyBytes, JwtHashAlgorithm algorithm)
    {
        var segments = new List<string>();
        var header = new { alg = algorithm.ToString(), typ = "JWT" };

        byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header, Formatting.None));
        byte[] payloadBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload, Formatting.None));

        segments.Add(Base64UrlEncode(headerBytes));
        segments.Add(Base64UrlEncode(payloadBytes));

        var stringToSign = string.Join(".", segments);

        var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);

        byte[] signature = HashAlgorithms[algorithm](keyBytes, bytesToSign);
        segments.Add(Base64UrlEncode(signature));

        return string.Join(".", segments.ToArray());
    }
        using (var wb = new WebClient())
        {
            var url = "https://www.googleapis.com/oauth2/v3/token/";
            wb.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
            var data2 = new NameValueCollection();
            data2["grant_type"] = "urn:ietf:params:oauth:grant-type:jwt-bearer";
            data2["assertion"] = signedJwt;
            var response2 = wb.UploadValues(url, "POST", data2);
        }

感谢您的帮助:)

您在POST数据中包含了
内容类型
,但它应该作为HTTP头的一部分显示,如所示:

wb.Headers.Add("Content-Type","application/x-www-form-urlencoded");
但是,使用UploadValues,除非被覆盖,否则这将是默认设置

除此之外,UploadValues将自动对您的值进行URL编码,因此您应该以原始形式呈现它们;因此,对于赠款类型,这意味着:

data2["grant_type"] = "urn:ietf:params:oauth:grant-type:jwt-bearer";
编辑1:
此外,您的JWT使用了错误的
aud
声明,因为它被设置为
https://accounts.google.com/o/oauth2/token
而不是
https://www.googleapis.com/oauth2/v3/token
自2012年7月2日起过期

编辑2: 您还必须在不带尾随斜杠的情况下发布到URL,并获得正确的
iat
exp
时间戳。使用
Newtonsoft.Json
成功测试代码:

public class GoogleServiceAccountBearerJWTSample
{
    private static string Base64UrlEncode(byte[] input)
    {
        var output = Convert.ToBase64String(input);
        output = output.Split('=')[0]; // Remove any trailing '='s
        output = output.Replace('+', '-'); // 62nd char of encoding
        output = output.Replace('/', '_'); // 63rd char of encoding
        return output;
    }

    public static string Encode(object payload, AsymmetricAlgorithm rsa) {
        var segments = new List<string>();
        var header = new { alg = "RS256", typ = "JWT" };
        byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header, Formatting.None));
        byte[] payloadBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload, Formatting.None));
        segments.Add(Base64UrlEncode(headerBytes));
        segments.Add(Base64UrlEncode(payloadBytes));
        var stringToSign = string.Join(".", segments.ToArray());
        var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);

        // VARIANT A - should work on non-SHA256 enabled systems
        var rs = rsa as RSACryptoServiceProvider;
        var cspParam = new CspParameters
        {
            KeyContainerName = rs.CspKeyContainerInfo.KeyContainerName,
            KeyNumber = rs.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2
        };
        var aescsp = new RSACryptoServiceProvider(cspParam) { PersistKeyInCsp = false };
        var signature = aescsp.SignData(bytesToSign, "SHA256");
        // END OF VARIANT A

        // VARIANT B - works on FIPS SHA256 enabled systems
        // var pkcs1 = new RSAPKCS1SignatureFormatter(rsa);
        // pkcs1.SetHashAlgorithm("SHA256");
        // var signature = pkcs1.CreateSignature(new SHA256Managed().ComputeHash(bytesToSign));
        // END OF VARIANT B

        segments.Add(Base64UrlEncode(signature));
        return string.Join(".", segments.ToArray());
   }

   public static void Main()
   {    
        var utc0 = new DateTime(1970,1,1,0,0,0,0, DateTimeKind.Utc);
        var issueTime = DateTime.UtcNow;

        var iat = (int)issueTime.Subtract(utc0).TotalSeconds;
        var exp = (int)issueTime.AddMinutes(55).Subtract(utc0).TotalSeconds; // Expiration time is up to 1 hour, but lets play on safe side

        var payload = new {
            iss = "xxxxxxxxxxxxxxxxxx@developer.gserviceaccount.com",
            aud = "https://www.googleapis.com/oauth2/v3/token",
            scope = "https://www.googleapis.com/auth/freebase",
            exp = exp,
            iat = iat
        };

        var certificate = new X509Certificate2("google-client.p12", "notasecret");
        var signedJwt = Encode(payload, certificate.PrivateKey);

        //System.Console.WriteLine(signedJwt);

        using (var wb = new WebClient())
        {
            var url = "https://www.googleapis.com/oauth2/v3/token";
            var data2 = new NameValueCollection();
            data2["grant_type"] = "urn:ietf:params:oauth:grant-type:jwt-bearer";
            data2["assertion"] = signedJwt;
            var response2 = wb.UploadValues(url, "POST", data2);
            System.Console.WriteLine(Encoding.UTF8.GetString(response2));
        }
    }
}
public类GoogleServiceAccountBearerJWTSample
{
专用静态字符串Base64UrlEncode(字节[]输入)
{
var输出=Convert.tobase64字符串(输入);
output=output.Split('=')[0];//删除任何尾随'='
output=output.Replace('+','-');//编码的第62个字符
output=output.Replace('/',''');//编码的第63个字符
返回输出;
}
公共静态字符串编码(对象有效负载,非对称算法rsa){
var segments=新列表();
var header=new{alg=“RS256”,typ=“JWT”};
byte[]headerBytes=Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header,Formatting.None));
byte[]payloadBytes=Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload,Formatting.None));
添加(Base64UrlEncode(headerBytes));
添加(Base64UrlEncode(payloadBytes));
var stringToSign=string.Join(“.”,segments.ToArray());
var bytesToSign=Encoding.UTF8.GetBytes(stringToSign);
//变体A-应适用于未启用SHA256的系统
var rs=rsa作为rsa加密服务提供商;
var csparam=新的CSP参数
{
KeyContainerName=rs.CspKeyContainerInfo.KeyContainerName,
KeyNumber=rs.CspKeyContainerInfo.KeyNumber==KeyNumber.Exchange?1:2
};
var aescsp=new RSACryptoServiceProvider(csparam){PersistKeyInCsp=false};
var signature=aescsp.SignData(bytesToSign,“SHA256”);
//变体A的结尾
//变体B-适用于启用FIPS SHA256的系统
//var pkcs1=新的RSAPKCS1信号格式(rsa);
//pkcs1.SetHashAlgorithm(“SHA256”);
//var signature=pkcs1.CreateSignature(新的SHA256Managed().ComputeHash(bytesToSign));
//变体B的结尾
添加(Base64UrlEncode(签名));
返回字符串.Join(“.”,segments.ToArray());
}
公共静态void Main()
{    
var utc0=新的日期时间(1970,1,1,0,0,0,DateTimeKind.Utc);
var issueTime=DateTime.UtcNow;
var iat=(int)issueTime.Subtract(utc0).TotalSeconds;
var exp=(int)issueTime.AddMinutes(55).Subtract(utc0).TotalSeconds;//过期时间最长为1小时,但请谨慎行事
var有效载荷=新{
iss=”xxxxxxxxxxxxxxxxxx@developer.gserviceaccount.com",
澳元=”https://www.googleapis.com/oauth2/v3/token",
范围=”https://www.googleapis.com/auth/freebase",
exp=exp,
iat=iat
};
var certificate=newx509certificate2(“googleclient.p12”,“notasecret”);
var signedJwt=Encode(有效负载、证书.PrivateKey);
//系统控制台写入线(签名JWT);
使用(var wb=new WebClient())
{
变量url=”https://www.googleapis.com/oauth2/v3/token";
var data2=新的NameValueCollection();
数据2[“授权类型”]=“urn:ietf:params:oauth:grant-type:jwt-bearer”;
数据2[“断言”]=已签名的JWT;
var response2=wb.UploadValues(url,“POST”,data2);
System.Console.WriteLine(Encoding.UTF8.GetString(response2));
}
}
}

感谢您的回复。我按照您的建议更改了代码(如上所示),但不幸的是仍然收到相同的“400错误请求”错误。我做错了什么?参见附录answer@Hans你确定吗?JWT取自:[link]中的示例,我看到他们确实使用了[link],你是否看到了其他情况?好吧,那么问题的根本原因是:你不能拿一个JWT(就像谷歌示例中的JWT)来展示它。。。您需要在Google API控制台中生成自己的客户端和相关私钥,并使用该信息(电子邮件+私钥)创建和签署自己的JWT。创建自己的客户机的过程在中有很好的描述@mashtagidi:您可以为您的客户创建一个单独的问题issue@HansZ. 我在GoogleAPI控制台中生成了我自己的客户端和相关的私钥,并使用这些信息(电子邮件+私钥)创建和签署了我自己的JWT。但仍会收到相同的错误“400错误请求”。我在问题中添加了我的代码。
public class GoogleServiceAccountBearerJWTSample
{
    private static string Base64UrlEncode(byte[] input)
    {
        var output = Convert.ToBase64String(input);
        output = output.Split('=')[0]; // Remove any trailing '='s
        output = output.Replace('+', '-'); // 62nd char of encoding
        output = output.Replace('/', '_'); // 63rd char of encoding
        return output;
    }

    public static string Encode(object payload, AsymmetricAlgorithm rsa) {
        var segments = new List<string>();
        var header = new { alg = "RS256", typ = "JWT" };
        byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header, Formatting.None));
        byte[] payloadBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload, Formatting.None));
        segments.Add(Base64UrlEncode(headerBytes));
        segments.Add(Base64UrlEncode(payloadBytes));
        var stringToSign = string.Join(".", segments.ToArray());
        var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);

        // VARIANT A - should work on non-SHA256 enabled systems
        var rs = rsa as RSACryptoServiceProvider;
        var cspParam = new CspParameters
        {
            KeyContainerName = rs.CspKeyContainerInfo.KeyContainerName,
            KeyNumber = rs.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2
        };
        var aescsp = new RSACryptoServiceProvider(cspParam) { PersistKeyInCsp = false };
        var signature = aescsp.SignData(bytesToSign, "SHA256");
        // END OF VARIANT A

        // VARIANT B - works on FIPS SHA256 enabled systems
        // var pkcs1 = new RSAPKCS1SignatureFormatter(rsa);
        // pkcs1.SetHashAlgorithm("SHA256");
        // var signature = pkcs1.CreateSignature(new SHA256Managed().ComputeHash(bytesToSign));
        // END OF VARIANT B

        segments.Add(Base64UrlEncode(signature));
        return string.Join(".", segments.ToArray());
   }

   public static void Main()
   {    
        var utc0 = new DateTime(1970,1,1,0,0,0,0, DateTimeKind.Utc);
        var issueTime = DateTime.UtcNow;

        var iat = (int)issueTime.Subtract(utc0).TotalSeconds;
        var exp = (int)issueTime.AddMinutes(55).Subtract(utc0).TotalSeconds; // Expiration time is up to 1 hour, but lets play on safe side

        var payload = new {
            iss = "xxxxxxxxxxxxxxxxxx@developer.gserviceaccount.com",
            aud = "https://www.googleapis.com/oauth2/v3/token",
            scope = "https://www.googleapis.com/auth/freebase",
            exp = exp,
            iat = iat
        };

        var certificate = new X509Certificate2("google-client.p12", "notasecret");
        var signedJwt = Encode(payload, certificate.PrivateKey);

        //System.Console.WriteLine(signedJwt);

        using (var wb = new WebClient())
        {
            var url = "https://www.googleapis.com/oauth2/v3/token";
            var data2 = new NameValueCollection();
            data2["grant_type"] = "urn:ietf:params:oauth:grant-type:jwt-bearer";
            data2["assertion"] = signedJwt;
            var response2 = wb.UploadValues(url, "POST", data2);
            System.Console.WriteLine(Encoding.UTF8.GetString(response2));
        }
    }
}