我正在尝试从我构建的Swift应用程序连接到谷歌的Reply to Reviews API,这是https://www.googleapis.com/auth/androidpublisher范围的一部分,以便获得一个特定应用程序评论的列表。我创建了一个服务帐户,并用它创建了一个JWT令牌,然后尝试向API发出一个GET请求,但我得到了一个错误:
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "CREDENTIALS_MISSING",
"domain": "googleapis.com",
"metadata": {
"service": "androidpublisher.googleapis.com",
"method": "google.play.publishingapi.v3.ReviewsService.List"
}
}
]
}
}这是请求url:
https://www.googleapis.com/androidpublisher/v3/applications/<APP_PACKAGE>/reviews?access_token=<JWT-TOKEN>这是我的请求代码:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let auth = Authentication()
let jwt = auth.generateJWT()
self.retriveReviews(packageIdentifier: "<APP_PACKAGE>", auth: jwt!)
}
func retriveReviews(packageIdentifier: String, auth: String) {
let url = URL(string: "https://www.googleapis.com/androidpublisher/v3/applications/\(packageIdentifier)/reviews?access_token=\(auth)")
print("Request URL: \(url)")
var request = URLRequest(url: url!)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else { return }
print(String(data: data, encoding: .utf8)!)
}
task.resume()
}JWT令牌:
import JWTKit
import UIKit
class Authentication: NSObject {
func generateJWT() -> String? {
struct Header: JWTPayload {
enum CodingKeys: String, CodingKey {
case alg = "alg"
case type = "typ"
}
var alg = "RS256"
var type: String = "JWT"
func verify(using signer: JWTSigner) throws {
// print(self.expireTime > Date().timeIntervalSince1970)
fatalError()
}
}
struct Payload: JWTPayload {
enum CodingKeys: String, CodingKey {
case email = "iss"
case scope = "scope"
case aud = "aud"
case createdAt = "iat"
case expireTime = "exp"
}
var email: String = "XXXXX@XXXXXX.iam.gserviceaccount.com"
var scope: String = "https://www.googleapis.com/auth/androidpublisher"
var aud: String = "https://oauth2.googleapis.com/token"
var createdAt: Double = Date().timeIntervalSince1970
var expireTime: Double = Date().advanced(by: 1000).timeIntervalSince1970
func verify(using signer: JWTSigner) throws {
print(self.expireTime > Date().timeIntervalSince1970)
fatalError()
}
}
do {
if let certificatePath = Bundle.main.path(forResource: "k_created", ofType: "pem") {
let certificateUrl = URL(fileURLWithPath: certificatePath)
let certififcateData = try Data(contentsOf: certificateUrl)
let signers = JWTSigners()
let key = try RSAKey.private(pem: certififcateData)
signers.use(.rs256(key: key))
// MARK: HEADER NOT USED
let header = Header()
let payload = Payload()
let jwt = try signers.sign(payload)
// let jwt = try signers.sign(payload)
print("JWT: \(jwt)")
return jwt
} else {
return nil
}
} catch {
print(error)
return nil
}
}
}我做错了什么?还是我错过了一步?
发布于 2021-11-22 17:59:01
您似乎试图以查询参数的形式将访问令牌内联发送。您需要将其作为授权头发送。
curl \
'https://androidpublisher.googleapis.com/androidpublisher/v3/applications/[PACKAGENAME]/reviews' \
--header 'Authorization: Bearer [YOUR_ACCESS_TOKEN]' \
--header 'Accept: application/json' \
--compressed问题是你在做你应该做的access_token=\(auth)
request.setValue("Bearer " + accessToken, forHTTPHeaderField: "Authorization")授权需要在头中,如上面所示,并且它需要是一个有效的访问令牌。
是否运行了针对验证端点创建的JWT,以确保其甚至有效。如果您的代码有效,您将是我10年来第一个在不使用客户端libray的情况下从服务帐户凭据中创建访问令牌的人。干得好。
https://stackoverflow.com/questions/70070031
复制相似问题