2次传输:客户端->OSS
3次传输:客户端->服务端->OSS
虽然使用阿里云服务器传输到阿里云OSS属于内网传输有千兆带宽,但2次传输就是>3次传输,所以我考虑很久还是在自己的项目中用客户端直传方式,数据安全也有其他策略可以补救
使用STS临时访问凭证访问OSS
通过STS服务给其他用户颁发一个临时访问凭证。该用户可使用临时访问凭证在规定时间内访问您的OSS资源。临时访问凭证无需透露您的长期密钥,使您的OSS资源访问更加安全。
一、配置RAM用户与RAM角色
通过以下链接按步骤配置
https://help.aliyun.com/zh/oss/developer-reference/use-temporary-access-credentials-provided-by-sts-to-access-oss?spm=a2c4g.11186623.0.0.1fc27f7aX7rZHJ
注意: 配置到第四部即可,第四步的权限策略脚本中的Resource应该填写自己的bucket
“Resource”: “acs:oss:*:1021347314873735:bucketName/objectName” (其实就是访问路径,也可以是通配符 * )
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": "oss:PutObject",
"Resource": "acs:oss:*:1021347314873735:*/*"
}
]
}
配置中我们需要保存的信息:
二、通过SpringBoot获取临时访问凭证
-
在Maven工程中使用OSS Java SDK,只需在pom.xml中加入相应依赖即可。以3.15.1版本为例,在中加入如下内容:
<dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.15.1</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> <!-- no more than 2.3.3--> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> <version>2.3.3</version> </dependency>
-
创建oss配置类,将对应配置信息填写在application.yml文件中,当然你直接写死在代码里面也可以
@Configuration @ConfigurationProperties(prefix = "alioss") @Data public class AliOssConfig { // STS接入地址,例如sts.cn-hangzhou.aliyuncs.com。 String endpoint; // 填写步骤1生成的RAM用户访问密钥AccessKey ID和AccessKey Secret。 String accessKeyId ; String accessKeySecret; // 填写步骤3获取的角色ARN。 String roleArn; // 自定义角色会话名称,用来区分不同的令牌,例如可填写为SessionTest。 String roleSessionName; // 以下Policy用于限制仅允许使用临时访问凭证向目标存储空间examplebucket下的src目录上传文件。 // 临时访问凭证最后获得的权限是步骤4设置的角色权限和该Policy设置权限的交集,即仅允许将文件上传至目标存储空间examplebucket下的src目录。 // 如果policy为空,则用户将获得该角色下所有权限。 String policy ; // 设置临时访问凭证的有效时间为3600秒。 Long durationSeconds; // regionId表示RAM的地域ID。以华东1(杭州)地域为例,regionID填写为cn-hangzhou。也可以保留默认值,默认值为空字符串("")。 String regionId; String bucket; String region; } //以下为写到application.yml文件的配置信息,请根据代码注释自行编辑 alioss: endpoint: sts.cn-shenzhen.aliyuncs.com accessKeyId: 步骤一保存的RAM用户accessKeyId accessKeySecret: 步骤一保存的RAM用户accessKeySecret roleArn: 步骤一保存的RAM角色Arn policy: 这里我没写 durationSeconds: 900 regionId: 这里我没写 bucket: gulimall-jays region: oss-cn-shenzhen
-
创建controller给前端调用
@RestController
@RequestMapping("/ali-oss")
public class AliOssController{
@Autowired
private AliOssConfig aliOss;
@RequestMapping("/sts")
public Map<String, String> getStsInfo(AliOssConfig params){
try {
// 添加endpoint。适用于Java SDK 3.12.0及以上版本。
DefaultProfile.addEndpoint(aliOss.getRegionId(), "Sts", aliOss.getEndpoint());
// 构造default profile。
IClientProfile profile = DefaultProfile.getProfile(aliOss.getRegionId(), aliOss.getAccessKeyId(), aliOss.getAccessKeySecret());
// 构造client。
DefaultAcsClient client = new DefaultAcsClient(profile);
final AssumeRoleRequest request = new AssumeRoleRequest();
// 适用于Java SDK 3.12.0及以上版本。
request.setSysMethod(MethodType.POST);
request.setRoleArn(aliOss.getRoleArn());
//角色会话名称
request.setRoleSessionName(params.getRoleSessionName()); //这里我通过前端传参获取,到时候可以查看文件是谁传的
if(!aliOss.getPolicy().isEmpty()) request.setPolicy(aliOss.getPolicy());
request.setDurationSeconds(aliOss.getDurationSeconds());
final AssumeRoleResponse response = client.getAcsResponse(request);
AssumeRoleResponse.Credentials credentials = response.getCredentials();
Map<String, String> result = new HashMap<String, String>();
result.put("accessKeyId",credentials.getAccessKeyId());
result.put("accessKeySecret",credentials.getAccessKeySecret());
result.put("expiration",credentials.getExpiration());
result.put("securityToken",credentials.getSecurityToken());
result.put("region",aliOss.getRegion());
result.put("bucket",aliOss.getBucket());
return result
} catch (ClientException e) {
return null;
}
}
}
三、前端上传文件
直接使用阿里云提供的Browser.js
sdk文档链接: https://help.aliyun.com/zh/oss/developer-reference/browser-js/?spm=a2c4g.11186623.0.0.31ea1c58GmDGPS
1. 跨域了设置跨域资源共享(CORS)
- sdk安装: npm install ali-oss
- 调用接口获取配置信息初始化OSS实例并上传文件
import OSS from 'ali-oss'
import axios from "@/utils/request";
/**
* 获取oss签名
* @param params 查询条件
*/
export async function getAliOssSts(params) {
const res = await axios.get('/file/ali-oss/sts', {
params
});
if (res.data.code === 0) {
return res.data.data);
}
return Promise.reject();
}
export async function uploadFile(params, onUploadProgress){
try {
let stsConfig = await getAliOssSts({roleSessionName:"junjie"})
const client = new OSS({
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
region: stsConfig.region,
// 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
accessKeyId: stsConfig.accessKeyId,
accessKeySecret: stsConfig.accessKeySecret,
// 从STS服务获取的安全令牌(SecurityToken)。
stsToken: stsConfig.securityToken,
// 填写Bucket名称,例如examplebucket。
bucket: stsConfig.bucket,
});
let result = null;
if(params.file.size>= 4 * 1024 * 1024){ //大于4M分片上传
result = await client.multipartUpload(params.key, params.file, {
// 获取分片上传进度、断点和返回值。
progress: (p, cpt, res) => {
onUploadProgress&&onUploadProgress(p)
},
// 设置并发上传的分片数量。
parallel: 4,
// 设置分片大小。默认值为1 MB,最小值为100 KB。
partSize: 1024 * 1024,
// headers,
// 自定义元数据,通过HeadObject接口可以获取Object的元数据。
mime: "text/plain",
timeout: 120000 // 设置超时时间
});
}else{ //小于4M直接上传
result = await client.put(params.data.key, params.file)
}
return result;
}catch (e){
return Promise.reject(new Error(e));
}
}
四、客户端直传安全问题
-
服务端返回sts信息前进行加密处理,客户端接收数据后进行解密,这一块根据业务自行处理
-
浏览器插入禁止调试脚本
(() => {
function block() {
if (window.outerHeight - window.innerHeight > 200 ||window.outerWidth - window.innerWidth > 200) {
alert("检测到非法调试,任何敏感信息已进行加密处理,长时间启动开发者工具服务器将进行ip与账号封禁,请火速关闭!")
document.body.innerHTML ="检测到非法调试,任何敏感信息已进行加密处理,长时间启动开发者工具服务器将进行ip与账号封禁,请火速关闭!";
}
setInterval(() => {
(function () {
return false;
}
["constructor"]("debugger")
["call"]());
}, 50);
}
try {
block();
} catch (err) {}
})();
- 服务端接口调用日志记录,限制客户端用户调用接口次数。