【发布时间】:2018-08-14 01:26:28
【问题描述】:
尝试使用 Powershell HTTP/REST 并按照本教程实现 Firebase Admin SDK 服务帐户访问(Powershell 中没有方便的 API);
Using OAuth 2.0 for Server to Server Applications
形成 JWT 标头和 JWT 声明集非常简单,我可以重现本教程中的示例,但这就是棘手的地方;
使用从 Google API 控制台获得的私钥使用 SHA256withRSA(也称为带有 SHA-256 哈希函数的 RSASSA-PKCS1-V1_5-SIGN)对输入的 UTF-8 表示进行签名。输出将是一个字节数组。然后签名必须是 Base64url 编码的
这是我的相关代码 sn-p(感谢 @Will_Nevis 提供线索)
...
$jws = "$encodedheader.$encodedclaim";
$encodedjws = [System.Text.Encoding]::UTF8.GetBytes($jws);
$rsaobj = New-Object System.Security.Cryptography.RSACryptoServiceProvider;
$rsaobj.FromXmlString($rsaobj.ToXmlString($jsonfile.private_key));
$sha256OID = [System.Security.Cryptography.CryptoConfig]::MapNameToOID("SHA256");
$signature = $rsaobj.SignData($encodedjws, $sha256OID);
$encodedsignature = [System.Convert]::ToBase64String($signature);
$encodedsignature = $encodedsignature.Split('=')[0]
$encodedsignature = $encodedsignature.Replace('+', '-')
$encodedsignature = $encodedsignature.Replace('/', '_')
$jwt = "$encodedheader.$encodedclaim.$encodedsignature"
...
它生成了一个令人印象深刻的签名,比教程示例短,尽管我不知道它是否正确。它实际上不起作用(400)错误请求。
上面的代码是错误的还是在Powershell中有其他方法可以做到这一点..?
我想正确生成签名很重要。
感谢这个问题以前被问过,但似乎没有人“确定”它
以下是为我的 Firebase Admin SDK 服务帐号生成的 Json 私钥文件示例。这就是生成令牌所需的全部内容;
{
"type": "service_account",
"project_id": "abc-xyz",
"private_key_id": "nL9zQkSB1GXwF49MNcaEgCp9i7BmFr9JCBKYwgg",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvADANB_massive_key... 03i8lG\nrlsDWw==\n-----END PRIVATE KEY-----\n",
"client_email": "firebase-adminsdk-fuhti@abc-xyz.iam.gserviceaccount.com",
"client_id": "156461654611800605490",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fuhti%40abc-xyz.iam.gserviceaccount.com"
}
测试场景
([system.security.cryptography.rsacryptograpgyserviceprovider]::create(2048)).toxmlstring($true)
产生这段 XML(为了可读性而截断的值)“D”显然是 privateExponent(private_key?)
<RSAKeyValue>
<Modulus>2htVi ... Fay9qQ==</Modulus>
<Exponent>AQAB</Exponent>
<P>4dOudM8 ... t0JM=</P>
<Q>9z+W6qw ... p+KlM=</Q>
<DP>lOgN6 ... tbApX0=</DP>
<DQ>h75s0 ... w93Jys=</DQ>
<InverseQ>dDFa8H ... BlTuWs=</InverseQ>
<D>n4EN9rDQm ... Nj7lY7G4Q==</D>
</RSAKeyValue>
这几乎证实了这行代码完全没有任何作用
$rsaobj.FromXmlString($rsaobj.ToXmlString($jsonfile.private_key));
【问题讨论】:
-
看来 google 为其 API 提供了 .Net 包装器,并且 powershell 应该能够很好地使用任何 .net 代码。您是否已经探索过这条道路?
-
您的代码中有一件值得注意的事情。它似乎只将私钥传递给 RSACryptoProvider,但documentation 表示它需要公钥或公钥和私钥。
-
还有更多可疑之处。 RSA.toXMLString 的文档采用布尔值。它似乎正在导出现有的密钥对,布尔值确定是否包含私钥数据。它不需要字符串,尽管 powershell 可能会将字符串重新解释为
$true -
不,我认为 RSACryptoServiceProvider 可能是正确的方法,只是从外部源初始化很复杂。我认为你是对的,用私钥签名哈希不应该需要公钥,但是......这就是文档中写的内容。
-
@rangi 你有没有想过这个问题?我遇到了同样的问题,我也在使用 PowerShell。
标签: powershell oauth-2.0 rsa google-play-services