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

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,内容安全 1000次 1年
对象存储 OSS,恶意文件检测 1000次 1年
简介: oss服务端签名后直传分析与代码实现

1.简介

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

1.1 普通上传方式

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

1.2 服务端签名后直传

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

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

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

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

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测试

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 解决阿里云跨域问题


相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
相关文章
|
6月前
|
对象存储
minio临时凭证直传切换到阿里云oss
minio临时凭证直传切换到阿里云oss
512 1
|
6月前
|
弹性计算 前端开发 小程序
微信小程序上传文件至阿里云OSS直传(java后端签名+前端直传)
当前的通用文件上传方式是通过前端上传到服务器,再由服务器转存至对象存储。这种方式在处理小文件时效率尚可,但大文件上传因受限于服务器带宽,速度较慢。例如,一个100MB的文件在5Mbps带宽的阿里云ECS上上传至服务器需160秒。为解决此问题,可以采用后端签名的方式,使微信小程序直接上传文件到阿里云OSS,绕过服务器中转。具体操作包括在JAVA后端引入相关依赖,生成签名,并在微信小程序前端使用这个签名进行文件上传,注意设置正确的请求头和formData参数。这样能提高大文件上传的速度。
1109 1
|
1月前
|
存储 人工智能 开发工具
AI助理化繁为简,速取代码参数——使用python SDK 处理OSS存储的图片
只需要通过向AI助理提问的方式输入您的需求,即可瞬间获得核心流程代码及参数,缩短学习路径、提升开发效率。
1432 4
AI助理化繁为简,速取代码参数——使用python SDK 处理OSS存储的图片
|
16天前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
6月前
|
SQL 分布式计算 监控
基于阿里云 EMR Serverless Spark 版快速搭建OSS日志分析应用
本文演示了使用 EMR Serverless Spark 产品搭建一个日志分析应用的全流程,包括数据开发和生产调度以及交互式查询等场景。
56595 7
基于阿里云 EMR Serverless Spark 版快速搭建OSS日志分析应用
|
6月前
|
弹性计算 监控 Serverless
Serverless 应用引擎操作报错合集之阿里函数计算中调用zip-oss-fc函数返回时候出现错误代码如何解决
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
Serverless 应用引擎操作报错合集之阿里函数计算中调用zip-oss-fc函数返回时候出现错误代码如何解决
|
5月前
|
存储 分布式计算 关系型数据库
实时数仓 Hologres产品使用合集之是否提供相应的功能接口和指令,可以将数据从OSS存储同步到Hologres中进行分析
实时数仓Hologres的基本概念和特点:1.一站式实时数仓引擎:Hologres集成了数据仓库、在线分析处理(OLAP)和在线服务(Serving)能力于一体,适合实时数据分析和决策支持场景。2.兼容PostgreSQL协议:Hologres支持标准SQL(兼容PostgreSQL协议和语法),使得迁移和集成变得简单。3.海量数据处理能力:能够处理PB级数据的多维分析和即席查询,支持高并发低延迟查询。4.实时性:支持数据的实时写入、实时更新和实时分析,满足对数据新鲜度要求高的业务场景。5.与大数据生态集成:与MaxCompute、Flink、DataWorks等阿里云产品深度融合,提供离在线
|
6月前
|
存储 安全 API
对象存储OSS产品常见问题之在URL中包含签名如何解决
对象存储OSS是基于互联网的数据存储服务模式,让用户可以安全、可靠地存储大量非结构化数据,如图片、音频、视频、文档等任意类型文件,并通过简单的基于HTTP/HTTPS协议的RESTful API接口进行访问和管理。本帖梳理了用户在实际使用中可能遇到的各种常见问题,涵盖了基础操作、性能优化、安全设置、费用管理、数据备份与恢复、跨区域同步、API接口调用等多个方面。
288 0
|
6月前
|
SQL 存储 分布式计算
Hologres实时湖仓能力增强,挑战5分钟加速分析OSS数据
5分钟快速使用Hologres实时湖仓能力,无需移动数据,直接加速读取存储于数据湖OSS上的Hudi、Delta、Paimon等格式类型的数据
|
6月前
|
DataWorks 算法 对象存储
这个问题可能是由于DataWorks和OSS之间的签名算法不一致导致的
这个问题可能是由于DataWorks和OSS之间的签名算法不一致导致的
44 2

热门文章

最新文章