实现文件上传阿里云OSS【前端Vue 后端 Eggjs】

3,948 阅读4分钟

1、注册阿里云并开通OSS服务

😛

2、采用WEB端直接上传至OSS的方式上传文件

2-1、采用STS临时授权的方式让WEB端直接访问OSS

1.某些用户可能需要直接访问OSS资源。

2.对于这部分用户,只需要生成一个临时访问凭证(通过阿里云STS服务为阿里云账号(或RAM用户)提供临时访问权限管理。)给用户使用即可,不需要关心权限撤销问题,临时访问凭证过期后会自动失效。

4.通过STS生成的临时访问凭证包括 安全令牌 (SecurityToken) STS AK(AccessKeyId和AccessKeySecret)

5.使用AccessKey方法与您在使用阿里云账户或RAM用户AccessKey发送请求时的方法相同。需要注意的是在每个向OSS发送的请求中必须携带安全令牌

sts-oss

更详细的介绍:阿里云User

2-2、配置OSS存储桶

创建一个名为blog-userdata的Bucket用于存储用户数据;

进入Bucket -> 权限管理-跨域设置

配置为

来源:设置为*。
允许 Methods:选中GETPOSTPUTDELETE以及HEAD。
允许 Headers:设置为*。
暴露 Headers:设置为ETag、x-oss-request-id和x-oss-version-id。

2-3、配置RAM访问控制

1、创建阿里云子账号。

云账号登录RAM控制台。 在左侧导航栏的人员管理菜单下,单击用户。 单击新建用户

  1. 输入登录名称显示名称
  2. 访问方式区域下,选择编程访问
  3. 单击确定,然后单击复制保存访问密钥(AccessKeyId 和 AccessKeySecret)。
  4. 选中创建的子账号,单击添加权限
  5. 添加权限页面,为已创建的子账号添加AliyunSTSAssumeRoleAccess权限。
  6. 单击确定

2、创建权限策略。

  1. 在左侧导航栏的权限管理菜单下,单击权限策略管理

  2. 单击新建权限策略

  3. 填写策略名称备注

  4. 配置模式选择脚本配置 为ossUsers添加ListObjects、PutObject、GetObject等权限,在策略内容中配置脚本示例如下:

{
    "Version": "1",
    "Statement": [
     {
           "Effect": "Allow",
           "Action": [
             "oss:ListObjects",
             "oss:PutObject",
             "oss:AbortMultipartUpload",
             "oss:GetObject"
           ],
           "Resource": [
             "acs:oss:*:*:blog-userdata",
             "acs:oss:*:*:blog-userdata/*"
           ]
     }
    ]
}

3.创建角色并记分配权限策略

  1. 在左侧导航栏,单击RAM角色管理
  2. 单击新建RAM角色,选择可信实体类型为阿里云账号,单击下一步
  3. 新建RAM角色页面,填写RAM角色名称备注
  4. 选择云账号当前云账号
  5. 单击完成,之后单击为角色授权
  6. 添加权限页面,选择自定义权限策略,添加步骤2中创建的权限策略。
  7. 获取这个角色的ARN 例如 acs:ram::13**********623:role/ramosstest

到此为止 我们 创建了一个阿里云子账户创建了OSS(blog-userdata)的权限策略创建了一个角色并分配了OSS(blog-userdata)的权限策略获取了这个角色的ARN

此步骤不明白的建议仔细阅读官方文档,多实践几遍😄

3、Eggjs 服务端接口实现

3-1、搭建Eggjs项目

略😛

不会的可以看我上一篇 用Eggjs 实现 RESTful API

3-2、实现TST授权接口

1.安装依赖 npm install @alicloud/sts-sdk

2.配置config参数

// ./config/config.default.js

// STS - OSS
config.sts = {
  endpoint: 'sts.aliyuncs.com', // 在中国内地,您可以直接使用该统一公网接入地址,也可以使用所在地域的接入地址。
  accessKeyId: 'LT************RVns', // check this from aliyun console
  accessKeySecret: 'oPe*************4Wn', // check this from aliyun console
};

3.配置路由

// ./app/.router.js

// Cloud
router.get('/api/v1/ossToken', app.jwt, controller.cloud.getStsToken);

4.controller

// ./app/controller/cloud.js

'use strict';

const Controller = require('egg').Controller;

const getTokenRule = {
  accountID: { type: 'string', required: true },
  roleName: { type: 'string', required: true },
};

class CloudController extends Controller {
  async getStsToken() {
    const { ctx } = this;
    ctx.validate(getTokenRule, ctx.query);
    // 处理逻辑
    const { code, body } = await ctx.service.cloud.getStsToken(ctx.query);
    // 返回响应体和状态码
    ctx.body = { ...body };
    ctx.status = code;
  }
}

module.exports = CloudController;


5.service

// ./app/service/cloud.js

'use strict';

const Service = require('egg').Service;
const StsClient = require('@alicloud/sts-sdk');

class CloudService extends Service {
  async getStsToken(query) {
    const { accountID, roleName } = query;
    const {
      endpoint,
      accessKeyId,
      accessKeySecret,
    } = this.config.sts;
    const sts = new StsClient({
      endpoint,
      accessKeyId,
      accessKeySecret,
    });
    /**
     * assumeRole(RoleArn,RoleSessionName)
     * RoleArn:指定角色的ARN。格式:acs:ram::$accountID:role/$roleName 。
     * RoleSessionName: 用户自定义参数。此参数用来区分不同的令牌,可用于用户级别的访问审计。
     */
    const res1 = await sts.assumeRole(
      `acs:ram::${accountID}:role/${roleName}`,
      'client_web'
    );
    console.log(res1);
    if (res1.Credentials.SecurityToken) {
      const res2 = await sts.getCallerIdentity();
      console.log(res2);
      return { code: 200, body: { status: true, msg: '获取成功', data: res1 } };
    }
    return { code: 500, body: { status: true, msg: '获取失败' } };
  }
}

module.exports = CloudService;


6.访问接口测试

$ curl --location --request GET 'http://localhost:7001/api/v1/ossToken?accountID=1332314452386623&roleName=ramosstest' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1ZmMzNWI4YjZiYmI2ODMzNmU3NTEyYjgiLCJuYW1lIjoi55So5oi3NzE5NzM1Iiwic3RhdHVzIjoxMDAsImlhdCI6MTYwNjcyNDk1NCwiZXhwIjoxNjA2ODExMzU0fQ.5pxEeb39H8_RDyclMraKxSW4hSrFw6333f-qeCBuFYw'

// 返回 *为省略
{
    "status": true,
    "msg": "获取成功",
    "data": {
        "SecurityToken": "CAIS8wF1q6Ft5B2yfSjIr**********dQMEUzFOG4Pw==",
        "AccessKeyId": "STS.NT7np***********36sLUaER",
        "AccessKeySecret": "C5rBieF**********4JnAm6rVYnvppEFqezw",
        "Expiration": "2020-11-31T04:53:23Z"
    }
}

4、Web端 Vue上传文件实现

1.安装依赖

npm install ali-oss --save

2.简单的demo

<template>
  <div>
    <button @click="getOssToken">获取token</button>
    <span>OSS 文件上传</span>
    <br />
    <input ref="file" type="file" id="uploadImage" @change="toUpload" />
    <br />
    上传后返回URl地址为:{{ imgUrl }}
    <img :src="imgUrl" />
  </div>
</template>
<script>
import OSS from 'ali-oss'
export default {
  data() {
    return {
      imgUrl: '',
      ossConfig: {
        accountID: '1332314452386623',
        roleName: 'ramosstest'
      },
      ossParameter: {}
    }
  },
  methods: {
    getOssToken() {
      this.axios
        .get('/api/v1/ossToken', {
          params: this.ossConfig
        })
        .then(res => {
          this.ossParameter = res.data.data
          console.log(this.ossParameter)
        })
    },
    toUpload() {
      console.log('准备上传')
      const files = this.$refs.file.files[0]
      const name = files.name
      console.log(files)
      const client = new OSS({
        region: 'oss-cn-hangzhou',
        accessKeyId: this.ossParameter.AccessKeyId,
        accessKeySecret: this.ossParameter.AccessKeySecret,
        bucket: 'blog-userdata',
        stsToken: this.ossParameter.SecurityToken
      })
      console.log('初始化完成')
      const that = this
      client
        .multipartUpload(name, files)
        .then(function(res) {
          const str = res.res.requestUrls[0]
          that.imgUrl = str.split('?')[0]
          console.log('上传成功!', str.split('?')[0])
        })
        .catch(err => {
          console.log(err)
        })
    }
  }
}
</script>


3.效果预览

返回上传地址为:blog-userdata.oss-cn-hangzhou.aliyuncs.com/xinxiaomeng…

总结

⚠️ 代码不够严谨,请勿copy上生产!

新手容易错在参数的配置,请一定仔细阅读官方文档。