Swift调用Google Reply to Reviews API返回401未认证错误如何解决
问题原因与修复方案
1. 核心逻辑错误:JWT用途错误
你自行生成的JWT是服务账号OAuth2流程的中间凭证,不能直接作为access_token调用Google API,需要先完成令牌交换步骤:
- 用你生成的JWT向
https://oauth2.googleapis.com/token发起POST请求,请求体格式为x-www-form-urlencoded,携带两个参数:grant_type:固定值urn:ietf:params:oauth:grant-type:jwt-bearerassertion:你生成的JWT字符串
- 该接口返回的响应中会包含正式的
access_token,有效期默认3600秒,只有这个令牌可以用于调用安卓开发者API。
2. 认证方式优化
拿到正式access_token后,建议放在HTTP请求头中传递,不要放在URL查询参数里,降低令牌泄露风险:
request.setValue("Bearer \(正式的access_token)", forHTTPHeaderField: "Authorization")
3. 额外配置检查项
- 你使用的服务账号必须已在Google Play Console中被添加为用户,且授予了查看/回复评论的对应权限,否则认证通过后也会触发权限报错。
- 签名JWT用的pem私钥必须是你在Google Cloud Console创建该服务账号时下载的官方密钥,不能使用自行生成的密钥,否则会触发签名校验失败。
- JWT的有效期配置不能超过3600秒,你当前设置的1000秒符合要求。
核心逻辑修改示例
// 新增:用自签名JWT换取正式access_token func exchangeJWTForAccessToken(jwt: String, completion: @escaping (String?) -> Void) { let url = URL(string: "https://oauth2.googleapis.com/token")! var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") let params = "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=\(jwt)" request.httpBody = params.data(using: .utf8) let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any], let accessToken = json["access_token"] as? String else { completion(nil) return } completion(accessToken) } task.resume() } // 修改获取评论的调用逻辑 override func viewDidLoad() { super.viewDidLoad() let auth = Authentication() guard let jwt = auth.generateJWT() else { return } // 先换令牌再调用API exchangeJWTForAccessToken(jwt: jwt) { accessToken in guard let token = accessToken else { return } self.retriveReviews(packageIdentifier: "<APP_PACKAGE>", auth: token) } } func retriveReviews(packageIdentifier: String, auth: String) { let url = URL(string: "https://www.googleapis.com/androidpublisher/v3/applications/\(packageIdentifier)/reviews")! var request = URLRequest(url: url) request.httpMethod = "GET" // 用请求头传认证信息 request.setValue("Bearer \(auth)", forHTTPHeaderField: "Authorization") 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() }
内容的提问来源于stack exchange,提问作者ytpm
相关产品推荐
相关产品推荐

