阿里云 OSS - 开通到使用、服务端签名直传(前后端代码 + 效果演示)

news2024/11/13 15:24:05

目录

开始

OSS 相关术语须知

阿里云 OSS 开通

阿里云 OSS 使用

官方文档教程

实战开发

阿里云 OSS 自动配置

环境配置

实战开发

服务端签名直传

概述

代码实现


开始


OSS 相关术语须知

中文

英文

说明

存储空间

Bucket

存储空间是您用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。(一般来讲,一个项目一个 Bucket)

对象/文件

Object

对象是OSS存储数据的基本单元,也被称为OSS的文件。对象由元数据(Object Meta)、用户数据(Data)和文件名(Key)组成。对象由存储空间内部唯一的Key来标识。

地域

Region

地域表示OSS的数据中心所在物理位置。您可以根据费用、请求来源等综合选择数据存储的地域。详情请查看OSS已经开通的Region。

访问域名

Endpoint

Endpoint表示OSS对外服务的访问域名。OSS以HTTP RESTful API的形式对外提供服务,当访问不同地域的时候,需要不同的域名。通过内网和外网访问同一个地域所需要的域名也是不同的。具体的内容请参见各个Region对应的Endpoint。

访问密钥

AccessKey

AccessKey,简称AK,指的是访问身份验证中用到的AccessKeyId和AccessKeySecret。OSS通过使用AccessKeyId和AccessKeySecret对称加密的方法来验证某个请求的发送者身份。AccessKeyId用于标识用户,AccessKeySecret是用户用于加密签名字符串和OSS用来验证签名字符串的密钥,其中AccessKeySecret 必须保密。

阿里云 OSS 开通

a)进入 阿里云官网,在搜索框中输入 OSS ,点击 “对象存储 OSS”

b)点击立即开通

c)点击管理控制台

d)创建一个 Bucket

阿里云 OSS 使用

官方文档教程

a)先创建 AccessKey(之后通过 OSS 上传文件都需要用到这里的 AccessKeyId 和 AccessKeySecret)

Ps: 子用户创建好之后,就可以拿到 AccessKeyId 和 AccessKeySecret,但是这个东西只能查看一次,所以一定要自己保管好!

接着还需要给这个子用户开通 Bucket 访问权限,如下:

b)API 文档教程

实战开发

a)引入依赖

        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.17.4</version>
        </dependency>

 如果使用的是Java 9及以上的版本,则需要添加JAXB相关依赖。添加JAXB相关依赖示例代码如下:

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.3</version>
        </dependency>

b)代码如下:

@SpringBootTest(classes = [ProductApplication::class])
class OSSTest {

    @Test
    fun test() {
        //endpoint 地域节点(bucket 的 概览中可以找到)
        val endpoint = "oss-cn-cnmdb.aliyuncs.com"
        val accessKeyId = "JLUOIUsuoUSobPUnoPJSF%&YTFSkl{op6mJvC"
        val accessKeySecret = "uJOIU989hUNIsadfjhoUIOGE1y42BJIOPHsfN"

        //创建 OSSClient 实例
        val ossClient = OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret)

        //上传文件流
        val inputStream = FileInputStream("D:/tmp/滑稽.gif")
        ossClient.putObject("gulimall-byd", "滑稽.gif", inputStream)

        //关闭 OSSClient
        ossClient.shutdown()
        println("上传完成")
    }

}

运行之后,就可以看到 OSS 上传成功,通过 URL 就可以直接访问,如下:

阿里云 OSS 自动配置

环境配置

本来想使用 SpringCloudAlibaba OSS 的,但是发现这玩意在 2023 版本里根本没有...   就自己写自动配置吧~

a)配置文件如下:

alibaba:
  oss:
    access-key: JLUOIUsuoUSobPUnoPJSF%&YTFSkl{op6mJvC
    secret-key: uJOIU989hUNIsadfjhoUIOGE1y42BJIOPHsfN
    endpoint: oss-cn-cnmdb.aliyuncs.com

b)自动配置如下:

import com.aliyun.oss.OSS
import com.aliyun.oss.OSSClientBuilder
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration
class OSSConfig {

    @Value("\${alibaba.oss.access-key}")
    private lateinit var accessKey: String

    @Value("\${alibaba.oss.secret-key}")
    private lateinit var secretKey: String

    @Value("\${alibaba.oss.endpoint}")
    private lateinit var endpoint: String

    @Bean
    fun ossClient(): OSS = OSSClientBuilder()
        .build(endpoint, accessKey, secretKey) //注意参数顺序

}

实战开发

import com.aliyun.oss.OSS
import jakarta.annotation.Resource
import org.cyk.gulimall.product.ProductApplication
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import java.io.FileInputStream
@SpringBootTest(classes = [ProductApplication::class])
class OSSTest {

    @Resource
    private lateinit var ossClient: OSS

    @Test
    fun test() {
        //上传文件流
        val inputStream = FileInputStream("D:/tmp/滑稽.gif")
        ossClient.putObject("gulimall-cyk", "滑稽.gif", inputStream)
        println("上传完成")
    }

}

服务端签名直传

概述

传统的,我们有两种方式将图片上传到 OSS:

a)前端请求 -> 后端服务器 -> OSS 

好处:在服务端上传,更加安全.

坏处:给服务器带来压力.

b)直接写在前端 js 代码中

好处:效率高,不用给服务器带来额外压力.

坏处:危险,用户直接可以看得到密钥信息.

因此最好的方式就是 服务端签名直传:用户直接去服务器请求获取上传签名(账号密码生成的防伪签名,一般有过期时间),校验安全,服务器就返回该用户的防伪签名,然后用户就可以拿着签名和要上传的文件,通过表单直接上传到 OSS 中.

代码实现

a)后端如下:

@RestController
@RequestMapping("/third/oss")
class OSSApi(
    private val ossClient: OSS
) {

    @Value("\${alibaba.oss.bucket}")
    private lateinit var bucket: String

    @Value("\${alibaba.oss.endpoint}")
    private lateinit var endpoint: String

    @Value("\${alibaba.oss.access-key}")
    private lateinit var accessKey: String

    @RequestMapping("/policy")
    fun policy(): Map<String, String> {
        val host = "https://$bucket.$endpoint"
        //这里可以配置上传文件到 以时间为前缀的文件夹 中
        val format = SimpleDateFormat("yyyy-MM-dd").format(Date())
        val dir = "$format/" //用户上传文件时指定前缀

        try {
            val expireTime = 30
            val expireEndTime = System.currentTimeMillis() + expireTime * 1000
            val expiration = Date(expireEndTime)
            // PostObject请求最大可支持的文件大小为5 GB,即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
            val policyConds = PolicyConditions();
            policyConds.run {
                addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
                addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
            }

            val postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            val binaryData = postPolicy.toByteArray(Charset.forName("utf-8"))
            val accessId = accessKey
            val encodedPolicy = BinaryUtil.toBase64String(binaryData);
            val postSignature = ossClient.calculatePostSignature(postPolicy);

            val respMap = LinkedHashMap<String, String>()
            respMap.run {
                put("accessid", accessId);
                put("policy", encodedPolicy);
                put("signature", postSignature);
                put("dir", dir);
                put("host", host);
                put("expire", (expireEndTime / 1000).toString());
            }
            return respMap
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return mapOf("msg" to "fail")
    }

}

b)前端如下:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <title>OSS web直传</title>
    <meta
            name="viewport"
            content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
    />
</head>
<body>
<h2>OSS web直传---在服务端用Node.js签名</h2>
<ol>
    <li>Bucket必须设置跨域,且允许Methods必须选中POST,否则无法执行表单上传。</li>
</ol>
<br />
<div>
    <input type="file" id="fileInput" name="fileInput" />
    <input type="button" value="开始上传" onclick="upload()" />
</div>
<script>
    function upload() {
        const tokenUrl = "http://127.0.0.1:10010/third/oss/policy";
        fetch(tokenUrl).then(async (res) => {
            const { policy, signature, accessid, host, dir, stsToken } =
                await res.json();

            let formData = new FormData();
            formData.append("success_action_status", "200"); // 指定成功上传时,服务端返回状态码200,默认返回204。
            formData.append("policy", policy);
            formData.append("signature", signature);
            formData.append("OSSAccessKeyId", accessid);
            if (stsToken) formData.append("x-oss-security-token", stsToken);

            const files = document.getElementById("fileInput").files;
            if (files.length === 0) {
                alert("请选择文件");
                return;
            }
            formData.append("key", dir + files[0].name); // 文件名
            formData.append("file", files[0]); // file必须为最后一个表单域

            const param = {
                method: "POST",
                body: formData,
            };
            fetch(host, param)
                .then((data) => {
                    console.log(data);
                    alert("上传成功");
                })
                .catch((error) => {
                    console.error("Error:", error);
                });
        });
    }
</script>
</body>
</html>

Ps:上述代码中的跨域问题,前面的步骤处理过~   忘了,可以再往前看看

c)效果演示

返回阿里云,就可以看到如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1904314.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Transformer-LSTM预测 | Matlab实现Transformer-LSTM多变量时间序列预测

Transformer-LSTM预测 | Matlab实现Transformer-LSTM多变量时间序列预测 目录 Transformer-LSTM预测 | Matlab实现Transformer-LSTM多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现Transformer-LSTM多变量时间序列预测&#xff0c;Transf…

IDEA发疯导致maven下载回来的jar不完整zip END header not found

IDEA发疯导致maven下载回来的jar不完整zip END header not found 具体报错 java: 读取D:\mavenRepository\com\alibaba\druid-spring-boot-starter\1.2.23\druid-spring-boot-starter-1.2.23.jar时出错; zip END header not foundjava: java.lang.RuntimeException: java.io.…

【Linux】进程间的通信----管道

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

暄桐教练日课·21天《线的初识》即将开始 一起感受线描的乐趣

林曦老师的直播课&#xff0c;是暄桐教室的必修课。而教练日课是丰富多彩的选修课&#xff0c;它会选出书法史/美术史上重要的、有营养的碑帖和画儿&#xff0c;与你一起&#xff0c;高效练习。而且暄桐教练日课远不止书法、国画&#xff0c;今后还会有更多有趣的课程陆续推出&…

【C++第十课 - stack_queue】stack、queue的使用、适配器模型stack、queue和priority_queue的底层实现、deque

目录 一、stack使用1、push2、pop3、empty4、top题目1、最小栈2、栈的压入、弹出序3、逆波兰表达式求值 二、queue的使用priority_queue习题 三、适配器stack的底层实现queue的底层实现priority_queue的底层实现仿函数/函数对象函数指针 四、deque 一、stack使用 stack是个容器…

深入探索Python库的奇妙世界:赋能编程的无限可能

在编程的浩瀚宇宙中&#xff0c;Python以其简洁的语法、强大的功能和广泛的应用领域&#xff0c;成为了众多开发者心中的璀璨明星。而Python之所以能够如此耀眼&#xff0c;很大程度上得益于其背后庞大的库生态系统。这些库&#xff0c;如同一块块精心雕琢的积木&#xff0c;让…

ffmpeg图片视频编辑器工具的安装与使用

title: ffmpeg图片视频编辑器工具的安装与使用 tags: [ffmpeg, 图片, 音频, 视频, 工具, 流媒体] categories: [工具, ffmpeg] FFmpeg是一个开源的命令行工具&#xff0c;广泛用于处理视频和音频文件&#xff0c;包括转换格式、剪辑、混流、解码、编码等。以下是一些基本的FFmp…

【全面讲解下iPhone新机官网验机流程】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

nginx配置反向代理-CSDN

客户需求 1、实现通过域名访问税金的发票服务&#xff08;路径格式要求&#xff1a;https://www.xxx.com&#xff09; nginx的部署 前提 1、客户在局域网内已实现通过https://ip:port/stms访问税金平台 2、客户已获取https的SSL证书 3、客户申请的外网ip和域名已绑定 部署…

为什么要设计DTO类

为什么要使用DTO类&#xff0c;下面以新增员工接口为例来介绍。 新增员工 1.1 需求分析和设计 1.1.1 产品原型 一般在做需求分析时&#xff0c;往往都是对照着产品原型进行分析&#xff0c;因为产品原型比较直观&#xff0c;便于我们理解业务。 后台系统中可以管理员工信息…

WEB自动化框架封装MySQL连接及sql断言教程

为了在Web自动化测试中连接MySQL数据库并进行SQL断言&#xff0c;您可以按照以下步骤&#xff1a; 安装MySQL Connector/Python驱动程序&#xff0c;并导入它。 使用Connector/Python创建一个连接对象&#xff0c;指定所需的主机名、用户名、密码和数据库名。 创建一个游标对…

linux-虚拟内存-虚拟cpu

1、进程&#xff1a; 计算机中的程序关于某数据集合上的一次运行活动。 狭义定义&#xff1a;进程是正在运行的程序的实例&#xff08;an instance of a computer program that is being executed&#xff09;。广义定义&#xff1a;进程是一个具有一定独立功能的程序关于某个…

【三维向量旋转】基于Matlab的三维坐标旋转

一、问题描述 若空间中存在三个点A,B,C&#xff0c;其中A点是不动点&#xff0c;B点是当前方向向量上的一个点&#xff0c;C是目标方向上的一个点。如果要让AB向量沿着BC方向进行旋转&#xff0c;使得AB最终旋转到AC。这个过程就是三维向量的旋转过程。我们关注的是这个过程&am…

JAVA 课设 满汉楼餐厅点餐系统

一、代码详解 1.总体结构展示 2.总体代码 2.1 libs文件 链接&#xff1a;https://pan.baidu.com/s/1nH-I7gIlsqyMpXDDCFRuOA 提取码&#xff1a;3404 2.2 配置的德鲁连接池 #keyvalue driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/mhl?rewriteBa…

爱了!8款超好用的PC端办公软件!

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频https://aitools.jurilu.com/ 你电脑中用的最久的软件是哪些&#xff1f;以下是否有你曾经使用过的软件呢&#xff1f;工欲善其事&#xff0c;必先利其器&#xff0c;今天继续…

打造属于自己的脚手架工具并发布到npm仓库

一、创建项目 使用 npm init -y 创建项目创建项目入口文件 index.js在 package.json 中添加 bin 字段使用 npm link 命令将文件映射至全局&#xff0c;使可以在本地测试 zp 命令 // "zp" 为用于全局执行脚手架的命令&#xff0c;vue-cli中使用的是vue命令 "bi…

STM32-I2C

本内容基于江协科技STM32视频学习之后整理而得。 文章目录 1. I2C通信1.1 I2C通信简介1.2 硬件电路1.3 I2C时序基本单元1.3.1 起始条件和终止条件1.3.2 发送一个字节1.3.3 接收一个字节1.3.4 发送应答和接收应答 1.4 I2C时序1.4.1 指定地址写1.4.2 当前地址读1.4.3 指定地址读…

利用docker搭建漏洞环境,使用SSRF+Redis写入centos以及ubuntu的公钥,实现免密登录

一、实验环境 kali:在kali中搭建docker容器环境&#xff0c;这里我主要是使用第一个&#xff1b; redis作为一种数据库&#xff0c;它可以将数据写入内存中去&#xff0c;我们通过利用ssrf请求&#xff0c;实现服务器对自己的公钥写入&#xff0c;从而实验免密登录&#xff1b;…

el-table 树形数据与懒加载 二级数据不展示

返回的数据中 children和hasChildren只能有一个&#xff0c;不能同时存在&#xff0c;否则加载数据会失败

优化后Day53 动态规划part11

LC1143最长公共子序列 1.dp数组的含义&#xff1a;dp[i][j]表示以下标i结尾的text1子序列和以下标j结尾的text2子序列的最长公共子序列 2. 初始化&#xff1a;跟LC718一样&#xff0c;i结尾的需要初始化&#xff0c;i-1结尾不需要初始化 3. 递推公式 如果charAt(i)charAt(j)&…