使用Dart gcloud包生成Cloud Storage签名URL遇签名不匹配错误
生成Cloud Storage签名URL时的SignatureDoesNotMatch问题
问题背景
Dart的gcloud包文档未涵盖生成Cloud Storage资源限时访问签名URL的内容。参考相关示例尝试创建签名URL,但持续收到错误:The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.
想了解示例中的stringToSign应包含什么内容。已持有具备Object Viewer权限的服务账号,使用生成的key.json文件获取访问密钥,且存储桶启用了统一访问控制(未启用对象级ACL)。
已尝试的无效签名方式
signer.sign(utf8.encode('https://storage.googleapis.com/$bucketName/$wordFile'))signer.sign(utf8.encode('https://storage.googleapis.com/$bucketName'))signer.sign(utf8.encode('$bucketName/$wordFile'))
编辑更新:按文档编写的代码
Future<String> getWavSignedUrl(String wordFile) async { const expiration = 172800; final bucketName = dotenv.env['cloudWavBucket']; final canonicalUri = '/$bucketName/$wordFile'; final dateTimeNow = DateTime.now().toUtc(); final expirationDateStamp = '${dateTimeNow.year}${dateTimeNow.month.toString().padLeft(2, '0')}${dateTimeNow.day.toString().padLeft(2, '0')}'; final expirationDateTimeStamp = '${dateTimeNow.toIso8601String().replaceAll('-', '').replaceAll(':', '').split('.')[0]}Z'; final clientEmail = accountCredentials.email; final credentialScope = '$expirationDateStamp%2Fus%2Fstorage%2Fgoog4_request'; final credential = '$clientEmail%2F$credentialScope'; Map<String, String> headers = {}; headers['host'] = '$bucketName.storage.googleapis.com'; final sortedHeaderKeys = headers.keys.toList()..sort(); var canonicalHeaders = ''; var signedHeaders = ''; for (var key in sortedHeaderKeys) { canonicalHeaders += '$key:${headers[key]?.toLowerCase()}\n'; signedHeaders += '$key;'; } signedHeaders = signedHeaders.substring( 0, signedHeaders.length - 1); // remove trailing ';' Map<String, dynamic> queryParameters = {}; queryParameters['X-Goog-Algorithm'] = 'GOOG4-RSA-SHA256'; queryParameters['X-Goog-Credential'] = credential; queryParameters['X-Goog-Date'] = expirationDateTimeStamp; queryParameters['X-Goog-Expires'] = expiration; queryParameters['X-Goog-SignedHeaders'] = signedHeaders; var canonicalQueryString = ''; final sortedQueryKeys = queryParameters.keys.toList()..sort(); for (var key in sortedQueryKeys) { canonicalQueryString += '$key=${queryParameters[key].toString()}&'; } canonicalQueryString = canonicalQueryString.substring( 0, canonicalQueryString.length - 1); // remove trailing '&' String canonicalRequest = [ 'GET', canonicalUri, canonicalQueryString, canonicalHeaders, signedHeaders, 'UNSIGNED-PAYLOAD' ].join('\n'); String canonicalRequestHash = base64.encode(utf8.encode(canonicalRequest)); final stringToSign = [ 'GOOG4-RSA-SHA256', expirationDateTimeStamp, credentialScope, canonicalRequestHash, ].join('\n'); final pem = accountCredentials.privateKey; final rsaKey = keyFromString(pem); final signer = RS256Signer(rsaKey); final signedRequestBytes = signer.sign(utf8.encode(stringToSign)); final base64EncodedSignedRequest = Uri.encodeQueryComponent(base64.encode(signedRequestBytes)); const schemeAndHost = 'https://storage.googleapis.com'; final signedUrl = '$schemeAndHost$canonicalUri?$canonicalQueryString&x-goog-signature=$base64EncodedSignedRequest'; return signedUrl; }
仍出现的错误
SignatureDoesNotMatch
访问被拒绝。我们计算出的请求签名与你提供的签名不匹配。请检查你的Google密钥和签名方法。
内容的提问来源于stack exchange,提问作者Denis Gathondu
相关产品推荐
相关产品推荐

