云端上传图片有几种流程:

  1. 前端将图片传给后端,后端将图片转化为byte数组,调用OSS的相关SDK进行上传(上传过程在后端进行,账号密码保存在后端)
  2. 前端直接上传图片(上传过程在前端进行,账号密码保存在前端)
  3. 前端发起上传图片请求给后端,后端通过OSS的账户密码生成一个访问令牌给前端,前端带着访问令牌进行上传文件(上传过程在前端进行,账号密码保存在后端)

流程分析:

如果上传过程在后端,需要将图片传递给后端,这样会增加后端服务器的压力,账号密码保存在后端比较安全,所以我们选择第三种方式上传图片

1. 创建阿里OSS管理空间以及Bucket

注册阿里云账号,找到OSS,点击创建Bucket(可以事先购买资源包,进行包年包月,不然默认使用的是按量计费,自己玩就默认的就行)

2. STS临时授权(创建RAM用户以及角色并分配权限)

根据官网描述阿里云官网STS,找到STS临时授权访问OSS

STS原理图:

oss上传response获取路径_oss上传response获取路径

建议阿里云账号创建的RAM用户来对OSS进行操作,因为本身的阿里云账号具有所有权限,直接用阿里云账号进行操作有隐患,所以创建一个RAM用户(相当于阿里云的子用户)

进入阿里云的RAM控制台

登录阿里云账号,之后进入RAM访问控制页面,点击用户=》创建用户

注意!!创建好RAM用户之后,会告诉你该用户的AccessKey ID和AccessKey Secret等信息,需要马上复制下来保存,离开页面之后就不再显示

之后,选中创建的RAM用户,单机添加权限,添加 AliyunSTSAssumeRoleAccess 权限

接下来,我们需要创建一种权限,用于赋予给一个角色的权限;根据业务需求

oss上传response获取路径_java_02

我们需要将该权限赋予一个角色,点击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对原生进行封装

cloud-alibaba OSS wiki

先导入依赖:

<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详细配置

创建规则,没有什么特殊要求的话全部写*即可