如题目:同时使用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中
用 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',
}
}

确实已经定位出来
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的无法使用。 我说的是这种情况无法使用。

测试不是我说的这种情况
https://github.com/eggjs/egg-oss/pull/9
如果还有问题你可以把你的场景提交一个测试用例


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

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


最终问题原因:
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',
所以能用

要解决这个问题有几种办法:
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)`
Most helpful comment
要解决这个问题有几种办法:
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配置,也不应该被合并