1、STS临时授权访问OSS
OSS 可以通过阿里云STS(Security Token Service)进行临时授权访问。通过STS,可以为第三方应用或子用户(即用户身份由自己管理的用户)颁发一个自定义时效和权限的访问凭证。
1、使用场景
对于您本地身份系统所管理的用户,例如您的App的用户、您的企业本地账号、第三方App的用户,将这部分用户称为联盟用户。此外,联盟用户还可以是您创建的能访问您的阿里云资源应用程序的用户。这些联盟用户可能需要直接访问OSS资源。
对于这部分联盟用户,通过阿里云STS服务为阿里云账号(或RAM用户)提供临时访问权限管理。您不需要透露云账号(或RAM用户)的长期密钥(如登录密码、AccessKey),只需要生成一个临时访问凭证给联盟用户使用即可。这个凭证的访问权限及有效期限都可以由您自定义。您不需要关心权限撤销问题,临时访问凭证过期后会自动失效。
通过STS生成的临时访问凭证包括安全令牌 (SecurityToken)、临时访问密钥STS AK(AccessKeyId和AccessKeySecret)。使用AccessKey方法与您在使用阿里云账户或RAM用户AccessKey发送请求时的方法相同。需要注意的是在每个向OSS发送的请求中必须携带安全令牌。
2、实现原理
以一个移动App举例。假设你是一个移动App开发者,打算使用阿里云OSS服务来保存App的终端用户数据,并且保证每个App用户之间的数据隔离,放置一个App用户获取到其他App用户的数据。你可以使用STS授权用户直接访问OSS。
使用STS授权用户直接访问OSS的流程如下:
App用户登录。App用户和云账号无关,它是App的终端用户,App服务器支持App用户登录。对于每个有效的App用户来说,需要App服务器能定义出每个App用户的最小访问权限。
App服务器请求STS服务获取一个安全令牌(SecurityToken)。在调用STS之前,App服务器需要确定App用户的最小访问权限(用RAM Policy来自定义授权策略)以及凭证的过期时间。然后通过扮演角色(AssumeRole)来获取一个代表角色身份的安全令牌(SecurityToken)。
STS返回给App服务器一个临时访问凭证,包括一个安全令牌(SecurityToken)、临时访问密钥(AccessKeyId和AccessKeySecret)以及过期时间。
App服务器将临时访问凭证返回给App客户端,App客户端可以缓存这个凭证。当凭证失效时,App客户端需要向App服务器申请新的临时访问凭证。例如,临时访问凭证有效期为1小时,那么App客户端可以每30分钟向App服务器请求更新临时访问凭证。
App客户端使用本地缓存的临时访问凭证去请求OSS API。OSS收到访问请求后,会通过STS服务来验证访问凭证,正确响应用户请求。
3、操作步骤
1、创建子账号
复制保存一下创建用户的accessKeyId和accessKeySecret,后面代码中会用到,然后点击添加权限,为其添加 AliyunSTSAssumeRoleAccess 权限。
2、创建权限策略
{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": [ "oss:PutObject" ], "Resource": [ "acs:oss:*:*:bucketName", "acs:oss:*:*:bucketName/*" ] } ]}
3、创建角色并记录角色ARN
为创建的角色添加第二步创建的自定义权限策略:
复制保存创建角色的ARN,后面代码中用到:
4、调用STS服务接口AssumeRole获取临时访问凭证
1、pom.xml文件添加依赖
com.aliyun aliyun-java-sdk-sts 3.0.0 com.aliyun aliyun-java-sdk-core 4.4.6
2、后端代码实现
@Configuration@ConfigurationProperties(prefix = "ali.oss")@Datapublic class AliOssConfig { private String endpoint; private String accessKeyId; private String accessKeySecret; private String roleArn; private String regionId; private String bucket;}ali: oss: endpoint: oss-cn-shenzhen.aliyuncs.com access-key-id: 用户的accessKeyId access-key-secret: 用户的accessKeySecret role-arn: 角色的ARN region-id: cn-shenzhen bucket: best-favorites
调用AssumeRole接口之后返回给前端的对象
@Data@Builderpublic class AliOssTokenVo { private String region; private String accessKeyId; private String accessKeySecret; private String stsToken; private String bucket;}
获取临时访问凭证的方法
@Overridepublic AliOssTokenVo getOssToken() throws ClientException { IClientProfile profile = DefaultProfile.getProfile(aliOssConfig.getRegionId(), aliOssConfig.getAccessKeyId(), aliOssConfig.getAccessKeySecret()); DefaultAcsClient client = new DefaultAcsClient(profile); final AssumeRoleRequest request = new AssumeRoleRequest(); request.setRoleArn(aliOssConfig.getRoleArn()); request.setRoleSessionName("best-favorites"); request.setDurationSeconds(1000L); AssumeRoleResponse respOnse= client.getAcsResponse(request); AssumeRoleResponse.Credentials credentials = response.getCredentials(); String accessKeyId = credentials.getAccessKeyId(); String accessKeySecret = credentials.getAccessKeySecret(); String securityToken = credentials.getSecurityToken(); return AliOssTokenVo.builder() .accessKeyId(accessKeyId) .accessKeySecret(accessKeySecret) .stsToken(securityToken) .region("oss-" + aliOssConfig.getRegionId()) .bucket(aliOssConfig.getBucket()) .build();}
3、前端代码实现
api,调用后端接口获取临时访问凭证ossToken
import service from '@/utils/request';export const getOssToken = () => service.get('/ali-oss/token');
store/modules/oss模块
import { getOssToken } from '@/api/business';const oss = { state: { accessKeyId: '', accessKeySecret: '', stsToken: '', region: '', bucket: '', }, mutations: { SET_OSS_TOKEN: (state, { accessKeyId, accessKeySecret, stsToken, region, bucket }) => { state.accessKeyId = accessKeyId; state.accessKeySecret = accessKeySecret; state.stsToken = stsToken; state.region = region; state.bucket = bucket; }, }, actions: { GetOssToken({ commit }) { return new Promise((resolve, reject) => { getOssToken() .then(res => { const ossToken = res.result; commit('SET_OSS_TOKEN', ossToken); resolve(ossToken); }) .catch(error => { reject(error); }); }); }, },};export default oss;
上传组件:
list-type="picture-card" :file-list="fileList" :before-upload="beforeUpload" :custom-request="customRequest" @preview="handlePreview" @change="handleChange" > Upload beforeUpload(file) { const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; if (!isJpgOrPng) { this.$message.error('只能上传图片!'); } const isLt10M = file.size / 1024 / 1024 <10; if (!isLt10M) { this.$message.error('上传图片必须小于10M!'); } return isJpgOrPng }, async handleUpload({ file }) { try { let ossToken = await this.$store.dispatch('GetOssToken'); const client = new OSS({ accessKeyId: ossToken.accessKeyId, accessKeySecret: ossToken.accessKeySecret, stsToken: ossToken.stsToken, region: ossToken.region, bucket: ossToken.bucket, }); let result = await client.put(file.name, file); console.log('result:', result); file.url = result.url; this.fileList = [...this.fileList, file]; this.$emit('uploadSuccess', file.url); this.$message.success('文件上传成功!'); } catch (e) { console.log(e); this.$message.error('文件上传失败!'); } },
由于是使用web端直传,点击上传之后可能会出现如下错误,说明阿里云oss需要配置一下跨域访问
点击确定之后,重新上传,可以看到这时就已经上传成功!
【文章转自日本站群多IP服务器 http://www.558idc.com/japzq.html提供,感恩】