云端上传图片有几种流程:
- 前端将图片传给后端,后端将图片转化为byte数组,调用OSS的相关SDK进行上传(上传过程在后端进行,账号密码保存在后端)
- 前端直接上传图片(上传过程在前端进行,账号密码保存在前端)
- 前端发起上传图片请求给后端,后端通过OSS的账户密码生成一个访问令牌给前端,前端带着访问令牌进行上传文件(上传过程在前端进行,账号密码保存在后端)
流程分析:
如果上传过程在后端,需要将图片传递给后端,这样会增加后端服务器的压力,账号密码保存在后端比较安全,所以我们选择第三种方式上传图片
1. 创建阿里OSS管理空间以及Bucket
注册阿里云账号,找到OSS,点击创建Bucket(可以事先购买资源包,进行包年包月,不然默认使用的是按量计费,自己玩就默认的就行)
2. STS临时授权(创建RAM用户以及角色并分配权限)
根据官网描述阿里云官网STS,找到STS临时授权访问OSS
STS原理图:
建议阿里云账号创建的RAM用户来对OSS进行操作,因为本身的阿里云账号具有所有权限,直接用阿里云账号进行操作有隐患,所以创建一个RAM用户(相当于阿里云的子用户)
进入阿里云的RAM控制台
登录阿里云账号,之后进入RAM访问控制页面,点击用户=》创建用户
注意!!创建好RAM用户之后,会告诉你该用户的AccessKey ID和AccessKey Secret等信息,需要马上复制下来保存,离开页面之后就不再显示
之后,选中创建的RAM用户,单机添加权限,添加 AliyunSTSAssumeRoleAccess
权限
接下来,我们需要创建一种权限,用于赋予给一个角色的权限;根据业务需求
我们需要将该权限赋予一个角色,点击RAM角色管理,创建新角色
填写好角色名等信息,接下来为角色分配权限,即我们刚刚根据业务创建的权限
走一遍流程
上面创建的这些东西都是干啥的?
前面我们说到,用阿里云账户直接操作有风险,所以我们创建了一个RAM用户来操作,我们为RAM用户添加了 AliyunSTSAssumeRoleAccess
权限,让其有权限来请求获取STS临时令牌
而想要获取STS临时令牌需要指定该令牌所充当的角色(即令牌有哪些权限),这就是我们前面创建的角色的意义
后端获取STS临时令牌(原生)
详细的示例也是在java SDK 地址里有写,我也是参考官网写的
在我们后端项目中如下:
先导入依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
controller代码
/**
* 获取上传图片的临时令牌
*/
@GetMapping("/upload")
public R upload () {
// 设置STS临时访问令牌
return brandService.getSTS();
}
有关我们RAM的用户信息配置在了application.yml文件中
# 阿里云OSS对象存储账号信息
OSS:
endpoint: sts.cn-shenzhen.aliyuncs.com # bucket的地区,这里是深圳,根据实际情况填写
access-key-id: RAM账号的access-key-id
access-key-secret: RAM账号的access-key-secret
role-arn: 角色的arn # 在角色详细信息中有
session-name: 角色的名字
service代码
@Value("${OSS.endpoint}")
private String endpoint;
@Value("${OSS.access-key-id}")
private String accessKeyId;
@Value("${OSS.access-key-secret}")
private String accessKeySecret;
@Value("${OSS.role-arn}")
private String roleArn;
@Value("${OSS.session-name}")
private String roleSessionName;
/**
* 给用户设置临时访问令牌
*/
@Override
public R getSTS() {
try {
// 添加endpoint(直接使用STS endpoint,第一个参数留空,无需添加region ID)
DefaultProfile.addEndpoint("", "Sts", endpoint);
// 构造default profile(参数留空,无需添加region ID)
IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
// 用profile构造client
DefaultAcsClient client = new DefaultAcsClient(profile);
final AssumeRoleRequest request = new AssumeRoleRequest();
request.setSysMethod(MethodType.POST);
request.setRoleArn(roleArn);
request.setRoleSessionName(roleSessionName);
request.setDurationSeconds(900L); // 设置凭证有效时间
final AssumeRoleResponse response = client.getAcsResponse(request);
Map<String, Object> map = new HashMap<>();
map.put("accessKeyId", response.getCredentials().getAccessKeyId());
map.put("accessKeySecret", response.getCredentials().getAccessKeySecret());
map.put("token", response.getCredentials().getSecurityToken());
// 将获取的令牌结果封装成map返回给前端
return R.ok(map);
} catch (ClientException e) {
e.printStackTrace();
return R.error("获取权限失败");
}
}
这样我们通过map封装了临时令牌的三个必须的信息accessKeyId,accessKeySecret,token,返回给前端
后端获取STS临时令牌(springcloud-alibaba)
通过springcloud alibaba对原生进行封装
先导入依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
</dependency>
在配置文件中配置access key等信息
之后直接自动注入
@Autowired
private OSS ossClient;
之后的用法跟原生的差不多
前端(vue)利用临时令牌上传图片
先安装相关SDK:cnpm install ali-oss --save
怎么操作,看官网上 Node.js的SDK(授权访问那一章节)
主要是利用后端传的三个令牌信息,创建client实例,就可以调用方法发送了
// 向后端发送请求获取令牌
const { data: result } = await this.$http({
url: this.$http.adornUrl('/upload'),
method: 'get'
})
if (result.code !== 0) {
this.$message.error(result.msg)
return
}
let OSS = require('ali-oss')
let cilent = new OSS({
region: 'oss-cn-shenzhen',
accessKeyId: result.accessKeyId,
accessKeySecret: result.accessKeySecret,
stsToken: result.token,
bucket: 'mall-nirvana'
})
let result = await client.put(fileName, file)
if (result.res.statusCode !== 200) {
this.$message.error('上传图片失败')
} else {
this.$message.success('上传成功')
}
跨域配置
在发送的过程中遇到了跨域问题,需要手动配置
点击进入bucket详细配置
创建规则,没有什么特殊要求的话全部写*即可