tencentyun / cos-js-sdk-v5

腾讯云 COS JS SDK(XML API)
https://cloud.tencent.com/product/cos
MIT License
329 stars 568 forks source link

后端返回临时秘钥,前端 COS.getAuthorization,然后请求返回 SignatureDoesNotMatch #47

Closed wanghengheng closed 5 years ago

wanghengheng commented 5 years ago

遇到了与 #35 差不多的问题,想问下当时具体是怎么解决的? @carsonxu

carsonxu commented 5 years ago

应该是用了自己构造PutObject接口请求。 可以参考demo/sts-put.html

wanghengheng commented 5 years ago

应该是用了自己构造PutObject接口请求。 可以参考demo/sts-put.html

谢谢回复先~

我发现是因为我在计算的时候,pathname 参数前面多了 ‘\’。。我的锅 修改之后,用原始秘钥可以上传成功了;但是使用临时秘钥的话,会返回 AccessDenied

carsonxu commented 5 years ago

STS 用这个 https://github.com/tencentyun/qcloud-cos-sts-sdk

wanghengheng commented 5 years ago

STS 用这个 https://github.com/tencentyun/qcloud-cos-sts-sdk

使用这个也是会返回 AccessDenied。

下面是部分 server 代码

    public Token temporaryToken2(String bucket) {
        //方式一
        TreeMap<String, Object> config = Maps.newTreeMap();
        try {
            config.put("SecretId", settings.getSecretId());
            config.put("SecretKey", settings.getSecretKey());
            config.put("durationSeconds", 1800);
            config.put("bucket", bucket(bucket));
            config.put("region", settings.getRegion());
            config.put("allowPrefix", "*");
            String[] allowActions = new String[]{
                    "name/cos:PutObject",
                    "name/cos:PostObject",
                    "name/cos:InitiateMultipartUpload",
                    "name/cos:ListMultipartUploads",
                    "name/cos:ListParts",
                    "name/cos:UploadPart",
                    "name/cos:CompleteMultipartUpload"
            };
            config.put("allowActions", allowActions);
            JSONObject credential = CosStsClient.getCredential(config);
            JSONObject credentials = credential.getJSONObject("credentials");
            return TencentTemporaryToken.builder()
                    .token(credentials.getString("sessionToken"))
                    .expire(credential.getLong("expiredTime"))
                    .secretId(credentials.getString("tmpSecretId"))
                    .secretKey(credentials.getString("tmpSecretKey"))
                    .build();
        } catch (Exception e) {
            throw new IllegalArgumentException("no valid secret !");
        }
    }

下面是部分前端代码:

//   计算 Authorization
               const COS = require("cos-js-sdk-v5");
                const Authorization = COS.getAuthorization({
                    SecretId: secretId,
                    SecretKey: secretKey,
                    Method: 'PUT',
                    Pathname: pathname,
                });

//     上传请求
        const { Authorization, XCosSecurityToken, pathname, bucket, appId } = info;
        const xhr = new XMLHttpRequest();
        xhr.open('PUT', api, true);
        xhr.setRequestHeader('Authorization', Authorization);
        xhr.setRequestHeader('x-cos-security-token', XCosSecurityToken);
        xhr.setRequestHeader('x-cos-storage-class', 'STANDARD');
        debugger;
        xhr.upload.onprogress = function (e) {
            console.log(`上传进度 ${(Math.round(e.loaded / e.total * 10000) / 100)}%`);
        };
        xhr.onload = function () {
            debugger;
            if (xhr.status === 200 || xhr.status === 206) {
                var ETag = xhr.getResponseHeader('etag');
                console.log(`上传成功:${ETag}`, xhr);
                // callback(null, {url: url, ETag: ETag});
            } else {
                console.log(`上传失败`, xhr, xhr.response);
            }
        };
        xhr.onerror = function (a) {
            debugger;
            console.log(`上传失败`, a);
        };
        xhr.send(data.file);
carsonxu commented 5 years ago

你上传是自己实现,可以不用SDK,用demo/sts-put.html

wanghengheng commented 5 years ago

你上传是自己实现,可以不用SDK,用demo/sts-put.html

嗯,自己实现是需要引入一下 CosAuth;用 sdk 的话,是用 COS.getAuthorization。。不过,这不是重点。。为什么会 AccessDenied 呢?

你看下上面的代码有什么问题么?或者根据下面的 requestId 可以解答一下我的疑问么?

附 临时秘钥的返回

{
  "credentials": {
    "tmpSecretId": "AKID6sORMowekMmMOkrvvHDqBW2XC_Dn2xTOTnkZbt346iVyFUXdHhsXC-vvdOypmEvQ",
    "tmpSecretKey": "uFXCz6jZi+LUNbGdB+05+uPoxZEo+Ft31GI3TxKzvsU=",
    "sessionToken": "EXkXo0m8CGUOeC4zulJtJwfKrLekCF2605f9887a90630e5ff7c59c86bde33d97SGWUBid23gvab75Ap1oKJWdPyTYpXP91S2IRX2lCsddh5cKEV0dRm-cyetTUaoQSndJT43TbSJ-OetavE153XJEVkV63Iw2t2kBME_qnD91Y98oJHeWuYIiO1U3yhjTC5xrSyZkJUOfgHRfjj6OxcLeV_Rq-Q2tOgT6J93DDS9LlgvStt1Vov8pGGTq2VHOxRPsTAq5nrikp66HX6zskAxJi1FIkCCCukt2n3jVML5a_MNCDkypHjQD7rvAanXrSauBwMS8wffvNb7rtG4PttWCgnTz8lkOCJToA1izEfIHIxhNmPGZgFvxO-xplgCtaqPRbL_AIu9LJwjVqiqsYWK9I89u2m67A-NcTxp6mxLCcr7nF13mg4gfqI_ZWU3CdFmXxl92MpQ_NIz0X-tQQg16ePFiY5AMdkTkmUzFqP36_8Wdh6Hn0MQF1BmtE70dY1HCU_vE1Noww4xSAONy3hK_0QVmklonKCyqCuT3J-d8"
  },
  "requestId": "134c09f7-c714-4539-8a57-1118763ebfd1",
  "startTime": 1551240709,
  "expiredTime": 1551242509
}

上传文件的返回:

<?xml version='1.0' encoding='utf-8' ?>
<Error>
        <Code>AccessDenied</Code>
        <Message>Access Denied.</Message>
        <Resource>coding-1251673040.cos.ap-guangzhou.myqcloud.com/account.csv</Resource>
        <RequestId>NWM3NjBlMmJfMWRiMjk0MGFfNjJlZV80OWEwMDA=</RequestId>
        <TraceId>OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTQyYWVlY2QwZTk2MDVmZDQ3MmI2Y2I4ZmI5ZmM4ODFjMGU5NjQzNGY1N2ZkZTM2MmQ2NzI2NGU1ZGIyNDgxZDc=</TraceId>
</Error>
wanghengheng commented 5 years ago

应该是用了自己构造PutObject接口请求。 可以参考demo/sts-put.html

谢谢回复先~

我发现是因为我在计算的时候,pathname 参数前面多了 ‘\’。。我的锅 修改之后,用原始秘钥可以上传成功了;但是使用临时秘钥的话,会返回 AccessDenied

这个,是因为前后端的 bucket 没有对上。