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

您所在的位置:网站首页 oss前端直传安全问题 oss服务端签名后直传分析与代码实现

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

2024-07-12 23:28| 来源: 网络整理| 查看: 265

文章目录 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核心配置 com.alibaba.cloud spring-cloud-alibaba-dependencies 2.1.0.RELEASE pom import com.alibaba.cloud spring-cloud-starter-alicloud-oss 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 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



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3