Egg: 请问同时使用egg-oss的 RAM和STS切换该如何设置,无法进行切换

Created on 10 Nov 2018  ·  21Comments  ·  Source: eggjs/egg

如题目:同时使用egg-oss的 RAM和STS改如何设置

比如我的需求是我既要给客户端使用sts,并且服务端不使用sts。
如果是ali-oss设置如下:

var oss = require('ali-oss');
var store = oss({
  accessKeyId: 'your access key',
  accessKeySecret: 'your access secret',
  bucket: 'your bucket name',
  region: 'oss-cn-hangzhou'
});

如上,我就能使用RAM

let OSS = require('ali-oss');
let STS = OSS.STS;
let sts = new STS({
  accessKeyId: '<子账号的AccessKeyId>',
  accessKeySecret: '<子账号的AccessKeySecret>'
});

如上,我就能使用STS模式

但是到了egg-oss,我设置了

 client: {
    sts: true,
    accessKeyId: '',
    accessKeySecret: '',
 }

我就没办法在切换非sts了。
如设置了非sts,app.oss.STS也拿不到。我需要能切换使用。请问这个是能做到的吗,在egg-oss中

Most helpful comment

image

要解决这个问题有几种办法:
1.文档内 clients下 default 不应该写上endpoint,这样会导致clients里面如果有一个是用的sts的情况,直接被这个default里面的endpoint合并掉,导致sts模式下不走https://sts.aliyuncs.com'

2.单独配置endpoint到bucket1,bucket2, 保证default下不能有配置endpoint. 如果sts的,可不配置endpoint,自动会走https://sts.aliyuncs.com'

3.源码里,只要配置是sts,任何情况下都不应该在被改变endpoint,也就是即使default里面有endpoint配置,也不应该被合并

exports.oss = {
  clients: {
    bucket1: {
      sts: true,
    },
    bucket2: {
      endpoint: 'http://oss-cn-shenzhen.aliyuncs.com',
    },
  },
  default: {
    accessKeyId: 'XXX',
    accessKeySecret: 'XXX',
    region: 'oss-cn-shenzhen',
    bucket: 'XXX',
  },
}

All 21 comments

用 clients 可以配多个

我对clients进行配置,并保证我有 bucket: 'junyao-files',

exports.oss = {
  clients: {
    bucket1: {
      sts: true,
      bucket: 'junyao-files',
    },
    bucket2: {
      bucket: 'junyao-files',
    },
  },
  default: {
    endpoint: 'oss-cn-shenzhen.aliyuncs.com',
    accessKeyId: 'XXX',
    accessKeySecret: 'XXX',
  },
}

而实际使用中:
1.使用bucket2

    const bucket2 = await app.oss.get('bucket2')
    const list = await bucket2.list();

能正常使用,说明bucket2正常。
2.使用bucket1

      const bucket1 = app.oss.get('bucket1')
      // console.log('bucket1', bucket1) 
      try {
        const token = await bucket1.assumeRole(roleArn, policy, tokenExpireTime, 'appointment')
        console.log('token', token)
      } catch (error) {
        console.log('error', error)
      }

正常输出bucket1为STS:

bucket1 STS {
  options:
   { endpoint: 'oss-cn-shenzhen.aliyuncs.com',
     format: 'JSON',
     apiVersion: '2015-04-01',
     sigMethod: 'HMAC-SHA1',
     sigVersion: '1.0',
     timeout: '60s',
     accessKeyId: 'XXX',
     accessKeySecret: 'XXX',
     sts: true,
     bucket: 'junyao-files',

但当使用
const token = await bucket1.assumeRole(roleArn, policy, tokenExpireTime, 'appointment')
时候
却报

error { Error: UnknownError: <?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>NoSuchBucket</Code>
  <Message>The specified bucket does not exist.</Message>
  <RequestId>5BE66F2E271EEE359CBEE88F</RequestId>
  <HostId>oss-cn-shenzhen.aliyuncs.com</HostId>
  <BucketName></BucketName>
</Error>

    at STS._requestError (/Users/hongjunyao/Desktop/egg_jueqi/node_modules/ali-oss/lib/sts.js:118:15)
    at STS.assumeRole (/Users/hongjunyao/Desktop/egg_jueqi/node_modules/ali-oss/lib/sts.js:105:28)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
  status: 404,
  message: 'UnknownError: <?xml version="1.0" encoding="UTF-8"?>\n<Error>\n  <Code>NoSuchBucket</Code>\n  <Message>The specified bucket does not exist.</Message>\n  <RequestId>5BE66F2E271EEE359CBEE88F</RequestId>\n  <HostId>oss-cn-shenzhen.aliyuncs.com</HostId>\n <BucketName></BucketName>\n</Error>\n',
  params:
   { agent: undefined,
     timeout: 60000,
     method: 'POST',
     content: 
....

而如果用之前单独 STS:

// exports.oss = {
//   client: {
//     sts: true,
//     accessKeyId: 'XXX',
//     accessKeySecret: 'XXX',
//   },
//   bucket: 'junyao-files',
//   region: 'oss-cn-shenzhen',
//   endpoint: 'oss-cn-shenzhen.aliyuncs.com',
//   timeout: '60s',
// }

却可正常输出token

 const token = await bucket1.assumeRole(roleArn, policy, tokenExpireTime, 'appointment')

附上我完整代码

exports.oss = {
  clients: {
    bucket1: {
      sts: true,
      bucket: 'junyao-files',
    },
    bucket2: {
      bucket: 'junyao-files',
    },
  },
  default: {
    endpoint: 'oss-cn-shenzhen.aliyuncs.com',
    accessKeyId: 'XXX',
    accessKeySecret: 'XXX',
  },
  // 以下配置权限参数,非OSS配置项,自定义用途
  policyFile: 'config/policy/all_policy.txt',
  roleArn: 'XXX',
  tokenExpireTime: '3600',
}

list()方法正常执行
assume_role() 无法正常执行

'use strict';
const path = require('path');
const fs = require('fs');
const MpUploadOssHelper = require('mp-upload-oss-helper');

const Controller = require('egg').Controller;

class OssController extends Controller {
  async assume_role() {
    const {
      ctx,
      service,
      app
    } = this;
    const {
      roleArn,
      policyFile,
      tokenExpireTime
    } = app.config.oss
    let policy
    if (policyFile) {
      policy = fs.readFileSync(path.resolve(policyFile)).toString('utf-8');
    }
    try {
      //1、生成sts临时访问权限参数
      const token = await app.oss.get('bucket1').assumeRole(roleArn, policy, tokenExpireTime, 'appointment')

      //2、生成签名参数
      const mpHelper = new MpUploadOssHelper({
        accessKeyId: token.credentials.AccessKeyId,
        accessKeySecret: token.credentials.AccessKeySecret,
        timeout: 1, // 限制参数的有效时间(单位: 小时)
        maxSize: 10 // 限制上传文件大小(单位: Mb)
      });

      // 生成的参数
      const sign = mpHelper.createUploadParams();

      console.log('签名sign', sign)

      const result = {
        region: app.config.oss.region,
        bucket: app.config.oss.bucket,
        accessKeyId: token.credentials.AccessKeyId,
        accessKeySecret: token.credentials.AccessKeySecret,
        stsToken: token.credentials.SecurityToken,
        expiration: token.credentials.Expiration,
        signature: sign.signature,
        policy: sign.policy,
        key: sign.key
      }
      ctx.helper.success({
        ctx,
        res: result
      })
    } catch (error) {
      ctx.helper.fail({
        ctx,
        res: error,
      })
    }
  }

  async list() {

    await this.listDir('jueqi/')

  }
  async listDir(dir) {
    const {
      ctx,
      service,
      app
    } = this;
    const list = await app.oss.get('bucket2').list({
      prefix: dir,
      delimiter: '/'
    });

    ctx.helper.success({
      ctx,
      res: list
    })
  }
}

module.exports = OssController;

@popomore

请问。。。

egg-oss 只保证了使用了 STS 客户端,具体逻辑还得问 ali-oss,分开两个 bucket 试试,一个单独授权 sts。

单独的都可以。只要这种配置的都不行,可见不是ali-oss的问题

exports.oss = {
  clients: {
    bucket1: {
      sts: true,
      bucket: 'junyao-files',
    },
    bucket2: {
      bucket: 'junyao-files',
    },
  },
  default: {
    endpoint: 'oss-cn-shenzhen.aliyuncs.com',
    accessKeyId: 'XXX',
    accessKeySecret: 'XXX',
  }
}

image

确实已经定位出来
clients 方式的 sts是用不了的。
单独的都可以

给 egg-oss 提个 test 吧

我加了测试是可以的 https://github.com/eggjs/egg-oss/pull/8

单个配置clients确实是可以阿
我的意思是配了clients 一个用sts 一个不用,这时候sts就用不了

@popomore 我看了你的测试,clients下只配置了一个 sts

需要

  clients: {
    bucket1: {
      sts: true,
      bucket: 'junyao-files',
    },
    bucket2: {
      bucket: 'junyao-files',
    },
  },

clients 两个情况下,一个是sts,这个sts的就用不了。
其他任意使用一个都是可以的。

汇总情况是:
1.clients 下单独配一个,无论是不是sts,都是可以用的
2.clients 下,配置一个sts,一个不是sts, 非sts可以使用,sts的无法使用。 我说的是这种情况无法使用。

image
测试不是我说的这种情况

https://github.com/eggjs/egg-oss/pull/9

如果还有问题你可以把你的场景提交一个测试用例

image

image

这边发现了endpoint和我这边不一样的问题,最终也发现了是这个endpoint导致的
我这里很疑惑。我单独使用的时候用的是阿里云oss后台的endpoint,都可以
但这里我输出出来你的test的发现是这个endpoint :https://sts.aliyuncs.com'
而我发现使用oss-cn-shenzhen.aliyuncs.com 导致的问题

image
如果用我自己的oss所在的endpoint就报错
image

image

最终问题原因:

exports.oss = {
  clients: {
    bucket1: {
      sts: true,
    },
    bucket2: {},
  },
  default: {
    accessKeyId: 'XXXXX',
    accessKeySecret: 'XXXX',
    region: 'oss-cn-shenzhen',
    bucket: 'biaojingli-test',
    endpoint: 'http://oss-cn-shenzhen.aliyuncs.com',  //当这里配置了endpoint,合并default和bucket1时候,sts使用了:http://oss-cn-shenzhen.aliyuncs.com,导致了sts无效
    timeout: '60s',
  }
}

不使用clients 使用client情况,无论endpoint配置什么,sts永远走:endpoint:'https://sts.aliyuncs.com',
所以能用

image

要解决这个问题有几种办法:
1.文档内 clients下 default 不应该写上endpoint,这样会导致clients里面如果有一个是用的sts的情况,直接被这个default里面的endpoint合并掉,导致sts模式下不走https://sts.aliyuncs.com'

2.单独配置endpoint到bucket1,bucket2, 保证default下不能有配置endpoint. 如果sts的,可不配置endpoint,自动会走https://sts.aliyuncs.com'

3.源码里,只要配置是sts,任何情况下都不应该在被改变endpoint,也就是即使default里面有endpoint配置,也不应该被合并

exports.oss = {
  clients: {
    bucket1: {
      sts: true,
    },
    bucket2: {
      endpoint: 'http://oss-cn-shenzhen.aliyuncs.com',
    },
  },
  default: {
    accessKeyId: 'XXX',
    accessKeySecret: 'XXX',
    region: 'oss-cn-shenzhen',
    bucket: 'XXX',
  },
}

解决方法:
config中配置:

exports.bucket1_sts = {
  sts: true,
  accessKeyId: '',
  accessKeySecret: '',
}
exports.bucket1 = {
  endpoint: 'https://oss-cn-hangzhou.aliyuncs.com',
  accessKeyId: '',
  accessKeySecret: '',
  bucket: '',
}

在需要oss操作的地方:
const bucket1_sts =this.oss.createInstance(this.app.config.bucket1_sts)`

Was this page helpful?
0 / 5 - 0 ratings