【发布时间】:2021-10-03 17:18:10
【问题描述】:
我是 Google API 的新手;我正在尝试在没有用户交互的情况下检索服务帐户的访问令牌。我读过这样做的方法是生成一个 JWT,然后向 API 运行一个请求,但是当我将 JWT 发送给 Google 时,我不断收到此错误:
{"error":"invalid_grant","error_description":"Invalid JWT Signature."}
这是生成 JWT 的代码:
extension Data {
func urlSafeBase64EncodedString() -> String {
return base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
}
}
struct Header: Encodable {
let alg = "RS256"
let typ = "JWT"
}
struct Payload: Encodable {
let iss = "content-uploader@project-id.iam.gserviceaccount.com"
let scope = "https://www.googleapis.com/auth/devstorage.full_control"
let aud = "https://oauth2.googleapis.com/token"
let iat = Date().timeIntervalSince1970
let exp = Date().timeIntervalSince1970.advanced(by: 1000)
}
let secret = "-----BEGIN PRIVATE KEY-----HERE IS A TON OF NUMBERS, SLASHES, PLUS SIGNS, GOING ON FOR HUNDREDS OF CHARACTERS. THIS WAS TAKEN FROM THE KEY DOWNLOADED AS A JSON FROM THE CREDENTIALS PAGE FOR THE SERVICE ACCOUNT IN GOOGLE CLOUD.\n-----END PRIVATE KEY-----\n"
let privateKey = SymmetricKey(data: secret.data(using: .utf8)!)
let headerJSONData = try! JSONEncoder().encode(Header())
let headerBase64String = headerJSONData.urlSafeBase64EncodedString()
let payloadJSONData = try! JSONEncoder().encode(Payload())
let payloadBase64String = payloadJSONData.urlSafeBase64EncodedString()
let toSign = (headerBase64String + "." + payloadBase64String).data(using: .utf8)!
let signature = HMAC<SHA256>.authenticationCode(for: toSign, using: privateKey)
let signatureBase64String = Data(signature).urlSafeBase64EncodedString()
let token = [headerBase64String, payloadBase64String, signatureBase64String].joined(separator: ".")
下面是正在运行的请求:
if let url = URL(string: "https://oauth2.googleapis.com/token?grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=\(token)") {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if data != nil {
print("Data: \(String(data: data!, encoding: .utf8)!)")
}
}.resume()
}
【问题讨论】:
-
1) 您不能直接使用服务帐户 JSON 密钥文件中的私钥 string。格式为 PEM。您必须加载 PEM 密钥并将其转换为库所需的格式(通常是二进制字符串)。检查您的库中是否有类似 getKeyStringFromPEM() 2) 私钥是非对称的(RSA 私钥),而不是对称的。 3) 我不会用 Swift 编写代码,所以希望我的提示会有所帮助。
-
在标题中设置“alg”="RS256 并稍后加载私钥,这都可以,但是然后您使用 HMAC
签名,这是错误的。我也不是Swift 编码器,但我相信您可以找到使用 RS256 签名的示例。 -
谢谢你们——我需要使用从 .p12 转换的 PEM 密钥切换到 RSA 和 RS256——它现在可以工作了。
标签: swift rest google-cloud-platform jwt