使用STS临时访问凭证通过客户端直连OSS对象存储服务器
导论
最近在做项目的过程中使用到了阿里云OSS来存储客户端上传的文件,方法是直接将客户端上传的文件发送到业务服务器,再通过业务服务器将文件上传到OSS对象存储服务器当中。
起初觉得是没问题的,但是在使用的过程中会发现上传文件的速度很慢,显然是受到业务服务器宽带的限制。为了解决这个问题我翻看了OSS的官方文档,在里面学到了不经过业务服务器的转发,而是直接让客户端和OSS服务器进行连接直接上传。下面为大家讲解一下在客户端直连OSS的操作过程。
借用阿里云的图例
企业A需首先创建RAM用户和RAM角色,并完成相关授权操作。之后,企业B向企业A申请临时访问凭证,企业A调用AssumeRole接口获取STS临时访问凭证,然后将其传递给企业B。企业B拿到该凭证后,即可将数据上传至企业A的OSS中。
前提条件: 企业A已创建Bucket。
总结
服务器代理上传和客户端直传相比,有三个缺点:
上传慢:用户数据需先上传到应用服务器,之后再上传到OSS。网络传输时间比直传到OSS多一倍。如果用户数据不通过应用服务器中转,而是直传到OSS,速度将大大提升。而且OSS采用BGP带宽,能保证各地各运营商之间的传输速度。
扩展性差:如果后续用户多了,应用服务器会成为瓶颈。
费用高:需要准备多台应用服务器。由于OSS上传流量是免费的,如果数据直传到OSS,不通过应用服务器,那么将能省下几台应用服务器。
步骤一
1.创建RAM用户
在阿里云主账户下或拥有访问控制(RAM)管理权限的RAM账号创建RAM用户。
注意:RAM用户的AccessKey Secret仅在创建时显示,后续将无法查看。因此,强烈建议及时下载包含访问密钥(AccessKey)的CSV文件,并妥善保存至本地。
2.为RAM用户授予请求AssumeRole的权限
通过主账号授予该RAM用户通过扮演角色调用STS服务的权限。
授予RAM用户调用STS服务AssumeRole接口的固定权限是AliyunSTSAssumeRoleAccess,与后续获取临时访问凭证以及通过临时访问凭证发起OSS请求所需权限无关。
3.创建RAM角色
使用阿里云主账号或拥有访问控制(RAM)管理权限的RAM账号创建RAM角色 。 用于定义RAM角色被扮演时,可以获得OSS服务的哪些访问权限。
单击ARN右侧的复制,保存角色的ARN
4. 为RAM角色授予上传文件的权限
创建完RAM角色后,使用阿里云主账号或拥有访问控制(RAM)管理权限的RAM账号为RAM角色附加一个或多个权限策略,明确RAM角色在被扮演时所能拥有的OSS资源访问权限。例如,如果希望RAM用户在扮演该角色后只能向OSS指定Bucket上传文件,则需要为角色添加写入权限的策略。
创建上传文件的自定义权限策略。 在创建权限策略页面中,单击脚本编辑,然后在策略文档输入框中赋予角色上传文件到examplebucket的权限。具体配置示例如下。
以下示例仅供参考。您需要根据实际需求配置更细粒度的授权策略,防止出现权限过大的风险。关于更细粒度的授权策略配置详情
RAM角色所拥有的OSS权限取决于Action的配置,例如授予oss:PutObject权限,则RAM用户在扮演RAM角色时可以对指定Bucket执行简单上传、表单上传、追加上传、分片上传、断点续传上传等操作。更多信息,请参见OSS Action说明。
创建完成后如下如所示
在这之后,给RAM角色coludapi授予自定义权限策略
5. 使用RAM用户扮演RAM角色获取临时访问凭证
注意:STS临时访问凭证无法通过阿里云主账号的访问密钥(AccessKey)调用STS API接口获取,否则会导致报错失败。以下示例将以使用RAM用户的访问密钥(AccessKey)为例进行操作。
- 为角色授予上传文件的权限后,RAM用户需要通过扮演角色来获取临时访问凭证。临时访问凭证包括安全令牌(SecurityToken)、临时访问密钥(AccessKeyId和AccessKeySecret)以及过期时间(Expiration)。可以使用STS SDK获取具有简单上传(
oss:PutObject)权限的临时访问凭证。有关更多语言的STS SDK示例,请参见STS SDK概览。 - 示例代码中的endpoint为STS服务接入点地址。为了获得更快的STS服务响应速度,可以根据服务器所处地域,选择对应的或相近的STS服务接入点地址进行填写。有关STS服务接入点地址信息,请参见服务接入点。
配置文件
oss:
access-key: LTAxxxxxxxxxAQ # → accessKeyId
secret-key: Pgxxxxxxxxxxxxxxxkx6 # → accessKeySecret
role-arn: acs:ram::19266xxx4109:role/clouapi # → roleArn
role-session-name: clouapi # → roleSessionName
expire: 3600 # → durationSeconds
region: cn-hangzhou # → regionId
依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>
代码实现:(企业B)
public CredentialsToken getCredentials() {
// 创建阿里云访问配置
DefaultProfile profile = DefaultProfile.getProfile(
OssConfiguration.region, // cn-hangzhou
OssConfiguration.accessKey, // RAM用户的
OssConfiguration.secretKey); // RAM用户的
IAcsClient client = new DefaultAcsClient(profile);
// 构造角色扮演请求
AssumeRoleRequest request = new AssumeRoleRequest();
request.setDurationSeconds(OssConfiguration.expire); // 3600
request.setRoleArn(OssConfiguration.roleArn); // clouapi角色
request.setRoleSessionName(OssConfiguration.roleSessionName); // clouapi
// 获取临时凭证
AssumeRoleResponse.Credentials response = client.getAcsResponse(request).getCredentials();
// 返回包装后的凭证对象
return new CredentialsToken(
response.getAccessKeyId(), // 临时AccessKeyId
response.getAccessKeySecret(), // 临时AccessKeySecret
response.getSecurityToken(), // SecurityToken
OssConfiguration.expire); // 有效期
}
将应用服务器获取到的STS临时访问凭证credentials传递给前端,前端通过解析credentials即可获得相应的凭证,从而通过凭证创建OSSClient并上传文件。
安全优势
- 临时性:凭证有时间限制,降低泄露风险
- 最小权限:只授予必要的操作权限
- 可审计:通过roleSessionName可以追踪使用情况
- 无需存储:不需要在客户端存储长期密钥
我在项目中通过重写大疆的一个抽象类AbstractMediaService,使得可以临时对我的oss进行访问 这些临时凭证主要用于:
- KMZ文件上传下载
- DJI Pilot设备文件传输
- 媒体文件管理
- 生成预签名URL
@Service
public class StorageServiceImpl extends AbstractMediaService implements IStorageService{
/**
* 获取STS临时凭证
* 用于DJI Pilot上传媒体和航线文件的临时访问权限
* @return 包含OSS访问信息和临时凭证的响应对象
*/
@Override
public StsCredentialsResponse getSTSCredentials() {
return new StsCredentialsResponse()
// 设置OSS访问端点
.setEndpoint(OssConfiguration.endpoint)
// 设置存储桶名称
.setBucket(OssConfiguration.bucket)
// 设置临时凭证信息
.setCredentials(ossService.getCredentials())
// 设置OSS服务提供商类型
.setProvider(OssConfiguration.provider)
// 设置对象键前缀(文件存储目录)
.setObjectKeyPrefix(OssConfiguration.objectDirPrefix)
// 设置区域信息
.setRegion(OssConfiguration.region);
}
}
参考: