oss服务端签名后直传分析与代码实现

news2024/11/16 5:48:40

文章目录

  • 1.简介
    • 1.1 普通上传方式
    • 1.2 服务端签名后直传
  • 3.服务端签名后直传文档
    • 3.1 用户向应用服务器请求上传Policy和回调。
    • 3.2 应用服务器返回上传Policy和签名给用户。
    • 3.3 用户使用Post方法向OSS发送文件上传请求。
  • 4.实战开发-后端
    • 4.1 pom.xml核心配置
    • 4.2 application.yml核心配置
    • 4.3 OssClientUtils工具类
    • 4.4 OssConfig配置类
    • 4.5 OssConstants常量类
    • 4.6 OssServiceController控制器
    • 4.7 Apifox测试
  • 5.注意事项和细节说明
    • 5.1 解决后端跨域问题
    • 5.2 解决阿里云跨域问题

1.简介

阿里云对象存储 OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存储服务,提供数据高可用性, 多种存储类型供选择,全面优化存储成本。

1.1 普通上传方式

image-20221113114912837

  • 上传慢:用户数据需先上传到应用服务器,之后再上传到OSS。网络传输时间比直传到OSS多一倍。如果用户数据不通过应用服务器中转,而是直传到OSS,速度将大大提升。
  • 扩展性差:如果后续用户多了,应用服务器会成为瓶颈。
  • 费用高:需要准备多台应用服务器。由于OSS上传流量是免费的,如果数据直传到OSS,不通过应用服务器,那么将能省下几台应用服务器。

1.2 服务端签名后直传

image-20221113115032842

  • Web端向服务端请求签名,然后直接上传,不会对服务端产生压力,而且安全可靠。
  • 但服务端无法实时了解用户上传了多少文件,上传了什么文件。如果想实时了解用户上传了什么文件,可以采用服务端签名直传并设置上传回调
  • 但存在着恶意上传的风险,造成存储空间的浪费

3.服务端签名后直传文档

🏠 https://help.aliyun.com/document_detail/31926.html

基于Post Policy的使用规则在服务端通过各种语言代码完成签名,然后通过表单直传数据到OSS。由于服务端签名直传无需将AccessKey暴露在前端页面,相比JavaScript客户端签名直传具有更高的安全性。

image-20221113145618805

3.1 用户向应用服务器请求上传Policy和回调。

请将客户端源码中的upload.js文件的如下代码片段的变量serverUrl的值设置为应用服务器的URL。

// serverUrl是用户获取签名和Policy等信息的应用服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
serverUrl = 'http://88.88.88.88:8888'

设置完成后,客户端会向该serverUrl发送Get请求来获取需要的信息。客户端源码下载地址,请参见aliyun-oss-appserver-js-master.zip。

本场景为服务端签名后直传,不涉及上传回调。因此,您需要注释客户端源码的upload.js文件内的'callback' : callbackbody字段,以关闭上传回调功能。

{
  'key' : key + '${filename}',
  'policy': policyBase64,
  'OSSAccessKeyId': accessid,
   // 设置服务端返回200状态码,默认返回204。
  'success_action_status' : '200', 
  'callback' : callbackbody,
  'signature': signature,
}

3.2 应用服务器返回上传Policy和签名给用户。

应用服务器侧的签名直传服务会处理客户端发送的Get请求消息,您可以设置对应的代码让应用服务器能够给客户端返回正确的消息。

以下是签名直传服务返回给客户端消息Body内容的示例:

{
"accessid":"LTAI5tBDFVar1hoq****",
"host":"http://post-test.oss-cn-hangzhou.aliyuncs.com",
"policy":"eyJleHBpcmF0aW9uIjoiMjAxNS0xMS0wNVQyMDoyMzoyM1oiLCJjxb25kaXRpb25zIjpbWyJjcb250ZW50LWxlbmd0aC1yYW5nZSIsMCwxMDQ4NTc2MDAwXSxbInN0YXJ0cy13aXRoIiwiJGtleSIsInVzZXItZGlyXC8i****",
"signature":"VsxOcOudx******z93CLaXPz+4s=",
"expire":1446727949,
"dir":"user-dirs/"
}

Body中的各字段说明如下:

字段描述
accessid用户请求的AccessKey ID。
host用户发送上传请求的域名。
policy用户表单上传的策略(Policy),Policy为经过Base64编码过的字符串。详情请参见Post Policy。
signature对Policy签名后的字符串。详情请参见Post Signature。
expire由服务器端指定的Policy过期时间,格式为Unix时间戳(自UTC时间1970年01月01号开始的秒数)。
dir限制上传的文件前缀。

3.3 用户使用Post方法向OSS发送文件上传请求。

new_multipart_params = {
     // key表示上传到Bucket内的Object的完整路径,例如exampledir/exampleobject.txtObject,完整路径中不能包含Bucket名称。
     // filename表示待上传的本地文件名称。
     'key' : key + '${filename}',
     'policy': policyBase64,
     'OSSAccessKeyId': accessid,
     // 设置服务端返回状态码为200,不设置则默认返回状态码204。
     'success_action_status' : '200',    
     'signature': signature,
 };

4.实战开发-后端

4.1 pom.xml核心配置

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.1.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
        <!--<version>2.1.0.RELEASE</version>-->
    </dependency>

4.2 application.yml核心配置

server:
  port: 9101
  max-http-header-size: 2MB
  servlet:
    context-path: /service
spring:
  cloud:
    alicloud:
      access-key: LTAI5tKcWoeuxTK8********
      secret-key: TQXiDtEnaR8Y7tXetvYZ0t********
      oss:
        endpoint: oss-cn-hangzhou.aliyuncs.com
        bucket: waveedu

4.3 OssClientUtils工具类

package com.zhulang.waveedu.sms.util;

import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.zhulang.waveedu.common.entity.Result;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author 狐狸半面添
 * @create 2023-01-29 1:36
 */

public class OssClientUtils {
    private OSS ossClient;
    private String accessId;

    private String endpoint;

    private String bucket;

    public OssClientUtils(OSS ossClient, String accessId, String endpoint, String bucket) {
        this.ossClient = ossClient;
        this.accessId = accessId;
        this.endpoint = endpoint;
        this.bucket = bucket;
    }


    public Result policy(String dirType) {
        // 1.指定填写Host地址,格式为https://bucketname.endpoint
        String host = "https://" + bucket + "." + endpoint;

        // 2.设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。
        String format = new SimpleDateFormat("/yyyy/MM/").format(new Date());
        String dir = dirType + format;

        Map<String, String> respMap = null;
        try {
            // 3.指定默认超时时间是30s
            long expireTime = 30;

            // 4.得到最终的截止时间
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);

            // 5.封装签名
            PolicyConditions policyConds = new PolicyConditions();
            // 5.1 设置可上传文件的大小,这里设置为 0 - 10MB
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 10485760);
            // 5.2 设置上传文件的前缀、可忽略
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
            // 5.3 对Policy签名后的字符串。
            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            // 6.用户表单上传的策略(Policy),Policy为经过Base64编码过的字符串。
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);

            // 7.封装签名直传服务返回给客户端消息Body内容
            respMap = new LinkedHashMap<>();
            // 7.1 用户请求的AccessKey ID。
            respMap.put("accessid", accessId);
            // 7.2 用户表单上传的策略(Policy),Policy为经过Base64编码过的字符串。
            respMap.put("policy", encodedPolicy);
            // 7.3 对Policy签名后的字符串。
            respMap.put("signature", postSignature);
            // 7.4 限制上传的文件前缀。
            respMap.put("dir", dir);
            // 7.5 用户发送上传请求的域名。
            respMap.put("host", host);
            // 7.6 由服务器端指定的Policy过期时间,格式为Unix时间戳(自UTC时间1970年01月01号开始的秒数)。
            respMap.put("expire", String.valueOf(expireEndTime / 1000));

        } catch (Exception e) {
            return Result.error();
        }
        return Result.ok(respMap);
    }

}

4.4 OssConfig配置类

package com.zhulang.waveedu.sms.config;

import com.aliyun.oss.OSS;
import com.zhulang.waveedu.sms.util.OssClientUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

/**
 * @author 狐狸半面添
 * @create 2023-01-29 1:41
 */
@Configuration
public class OssConfig {
    @Resource
    private OSS ossClient;

    @Value("${spring.cloud.alicloud.access-key}")
    private String accessId;

    @Value("${spring.cloud.alicloud.oss.endpoint}")
    private String endpoint;

    @Value("${spring.cloud.alicloud.oss.bucket}")
    private String bucket;

    @Bean
    public OssClientUtils ossClientUtils() {
        return new OssClientUtils(ossClient, accessId, endpoint, bucket);
    }


}

4.5 OssConstants常量类

package com.zhulang.waveedu.sms.constant;

/**
 * 与Oss相关的常量
 *
 * @author 狐狸半面添
 * @create 2023-01-29 1:55
 */
public class OssConstants {
    public static final String HEAD_IMAGE_DIR = "head-image";
}

4.6 OssServiceController控制器

package com.zhulang.waveedu.sms.controller;

import com.zhulang.waveedu.common.entity.Result;
import com.zhulang.waveedu.sms.constant.OssConstants;
import com.zhulang.waveedu.sms.util.OssClientUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
/**
 * @author 狐狸半面添
 * @create 2023-01-29 1:30
 */
@RestController
@RequestMapping("/oss")
public class OssServiceController {
    @Resource
    private OssClientUtils ossClientUtils;

    /**
     * 获取头像的签名
     *
     * @return 签名信息
     */
    @RequestMapping("/headImage")
    public Result headImage(){
        return ossClientUtils.policy(OssConstants.HEAD_IMAGE_DIR);
    }
}

4.7 Apifox测试

image-20230129160309981

5.注意事项和细节说明

5.1 解决后端跨域问题

package com.zhulang.waveedu.basic.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 解决跨域问题
 *
 * @author 狐狸半面添
 * @create 2023-01-15 23:08
 */
@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .maxAge(3600);
    }
}

5.2 解决阿里云跨域问题

image-20230129160804310

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

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

相关文章

Java两大工具库:Commons和Guava(2)

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客。值此新春佳节&#xff0c;我给您拜年啦&#xff5e;祝您在新的一年中所求皆所愿&#xff0c;所行皆坦途&#xff0c;展宏“兔”&#xff0c;有钱“兔”&#xff0c;多喜乐&#xff0c;常安宁&#xff01;开发中有一类应…

如何在es中查询null值

文章目录1、背景2、需求3、准备数据3.1 创建mapping3.2 插入数据4、查询 name字段为null的数据5、查询address不存在或值直接为null的数据6、参考链接1、背景 在我们向es中写入数据时&#xff0c;有些时候数据写入到es中的是null&#xff0c;或者没有写入这个字段&#xff0c;…

离散数学与组合数学-08谓词逻辑

文章目录离散数学与组合数学-08谓词逻辑8.1 谓词的引入8.1.1 引入谓词逻辑8.1.2 个体词与谓词8.2 量词的引入8.2.1 量词引入8.2.2 个体域符号化8.2.3 量词真值确定8.3 谓词符号化举例8.3.1 示例一8.3.2 示例二8.3.3 示例三8.3.4 示例四8.4 谓词合式公式8.4.1 四类符号8.4.2 项8…

MySQL运维(一)MySQL中的日志、Mysql主从复制

MySQL运维(一)MySQL中的日志、Mysql主从复制 1、MySQL日志 1.1 错误日志 错误日志是 MySQL 中最重要的日志之一&#xff0c;它记录了当 mysqld 启动和停止时&#xff0c;以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时&#…

Elasticsearch 需要了解的都在这

ES选主过程&#xff1f;其实ES的选主过程其实没有很高深的算法加持&#xff0c;启动过程中对接点的ID进行排序&#xff0c;取ID最大节点作为Master节点&#xff0c;那么如果选出来的主节点中存储的元信息不是最新的怎么办&#xff1f;其实他是分了2个步骤做这件事&#xff0c;先…

react 项目 中使用 Dllplugin 打包优化技巧

目录 0.React和DLLPlugin 前言 使用步骤 结果截图 主要说明 0.React和DLLPlugin React 是一个用于构建用户界面的 JavaScript 库。它由 Facebook 开发&#xff0c;现在由 Facebook 和一个由个人开发者和公司组成的社区维护。React 允许开发人员构建可重用的 UI 组件并有…

“回文子串、最长回文子序列”总结,动态规划再显神通(Java实现)

目录 一、回文子串 1.1、dp定义 1.2、递推公式 1.3、初始化 1.4、遍历顺序 1.5、解题代码 二、最长回文子序列 2.1、dp定义 2.2、递推公式 2.3、初始化 2.4、遍历顺序 2.5、解题代码 一、回文子串 题目描述&#xff1a; 题目来源&#xff1a;647. 回文子串 1.1、dp定…

解决使用copy.deepcopy()拷贝Tensor或model时报错只支持用户显式创建的Tensor问题

模型训练过程中常需边训练边做validation或在训练完的模型需要做测试&#xff0c;通常的做法当然是先创建model实例然后掉用load_state_dict()装载训练出来的权重到model里再调用model.eval()把模型转为测试模式&#xff0c;这样写对于训练完专门做测试时当然是比较合适的&…

ssm学生心理健康测评网的规划与设计

摘 要 1 Abstract 1 1 绪论 1 1.1 课题背景 1 1.2 课题研究现状 1 1.3 初步设计方法与实施方案 2 1.4 本文研究内容 2 2 系统开发环境 4 2.1 JSP技术介绍 4 2.2 B/S模式 4 2.3 MySQL环境配置 5 3 系统分析 6 3.1 系统可行性分析 6 3.1.…

【模糊神经网络】基于模糊神经网络的倒立摆轨迹跟踪控制

临近春节没啥事做&#xff0c;突然想起前两年未完成的模糊神经网络&#xff0c;当时是学了一段时间&#xff0c;但是到最后矩阵求偏导那块始终不对&#xff0c;最后也不了了之了&#xff0c;趁最近有空&#xff0c;想重新回顾回顾&#xff0c;看看会不会产生新的想法。经过不断…

elasticsearch基本操作

elasticsearch基本操作基础两种模式:ik分词器词库拓展索引库操作mapping映射属性typeindexanalyzerproperties索引库的CRUD创建修改查询删除文档操作创建查询修改删除基础 本教程使用es8.6.0与kibana作为测试环境 打开开发工具 ## 1.查看节点信息 GET /_cat/nodes?v ## 2.查…

【JUC并发编程】深入浅出Java并发基石——AQS

【JUC并发编程】深入浅出Java并发基石——AQS 参考资料&#xff1a; RedSpider社区——第十一章 AQS 深入剖析并发之AQS独占锁 1.5w字&#xff0c;30图带你彻底掌握 AQS&#xff01; 深入浅出AbstractQueuedSynchronizer 我画了35张图就是为了让你深入 AQS 动画演示AQS的核心原…

遍历 “可变参数模板” 的模板参数

类模板和函数模板&#xff0c;只能包含固定数量的模板参数&#xff0c;C11支持模板参数可变&#xff0c;那么在不知道模板参数有多少个的情况下&#xff0c;如何遍历模板参数&#xff1f; 目录 一、可变参数模板的声明 二、可变参数模板的遍历 1、递归遍历 2、非递归遍历 …

idea使用DataBase连接数据库 Free MyBatis Tool自动生成 实体类工具使用

DataBase DataBase连接数据库 设置DataSources Host 》IP地址Port 》端口号User 》用户名Password 》密码Database 》连接的数据库 设置驱动 Drives tables 文件夹中即所连接数据库中表 Free MyBatis Tool自动生成 实体类&#xff0c;Mapper &#xff0c;以及mapper.xml 选…

CleanMyMac4.12.3最新版本Mac系统清理工具

CleanMyMac可以为Mac腾出空间&#xff0c;软件已经更新到CleanMyMac X 支持最新版Macos 10.14系统。CleanMyMac具有一系列巧妙的新功能&#xff0c;可让您安全&#xff0c;智能地扫描和清理整个系统&#xff0c;删除大量未使用的文件&#xff0c;减小iPhoto图库的大小&#xff…

非类型模板参数/模板的特化/模板的分离编译

上一篇文章中&#xff0c;我们对模板有了初步的认识&#xff0c;接下来我们便对模板进一步地学习&#xff01; 1.非类型模板参数 模板参数分为类型形参与非类型形参&#xff1a; ①类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类…

20 个杀手级的 JavaScript 单行代码,可以节省你的编码时间

使用这些基本的单行代码将您的 JavaScript 技能提升到一个新的水平&#xff0c;这也将节省您的编码时间 &#x1f680;1) 查找数组中的最大值&#xff1a;Math.max(...array)2&#xff09;从数组中删除重复项&#xff1a;[...newSet(array)]3&#xff09;生成一个1到100之间的随…

Java开发环境搭建实践

前言 刚刚弄完python的环境搭建&#xff0c;今年打算也要好好学习Java&#xff0c;所以把Java的环境弄起来 搭建过程 jdk下载和安装 下载 官网&#xff1a;Oracle 甲骨文中国 | 云应用和云平台 打开官网 点击产品后下拉找到Java点进去。 下载Java 我就下载最新的jdk把…

Spring Boot学习之任务学习【异步、定时、邮件】

文章目录一 异步任务1.1 创建spring Boot项目&#xff0c;选择Spring Web1.2 创建AsyncService类1.3 编写controller类1.4 在启动类上开启异步功能1.5 测试结果二 定时任务2.1 基础知识2.2 项目创建2.3 创建一个ScheduledService2.4 在主程序上增加EnableScheduling 开启定时任…

Hbuilder打包成苹果IOS-App的详解

本文相关主要记录一下使用Hbuilder打包成苹果IOS-App的详细步骤。介绍一下个人开发者账号&#xff1a;再说下什么是免费的苹果开发者账号&#xff0c;就是你没交688年费的就是免费账号&#xff0c;如果你想变成付费开发者账号&#xff0c;提交申请付费就行&#xff0c;账号都是…