-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #76 from AlibabaCloudLandingZone/solution-oss-pre-…
…signed/0.0.1 solution-oss-pre-signed/0.0.1
- Loading branch information
Showing
15 changed files
with
913 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
target/ | ||
!.mvn/wrapper/maven-wrapper.jar | ||
!**/src/main/**/target/ | ||
!**/src/test/**/target/ | ||
|
||
### IntelliJ IDEA ### | ||
.idea/ | ||
|
||
### Eclipse ### | ||
.apt_generated | ||
.classpath | ||
.factorypath | ||
.project | ||
.settings | ||
.springBeans | ||
.sts4-cache | ||
|
||
### NetBeans ### | ||
/nbproject/private/ | ||
/nbbuild/ | ||
/dist/ | ||
/nbdist/ | ||
/.nb-gradle/ | ||
build/ | ||
!**/src/main/**/build/ | ||
!**/src/test/**/build/ | ||
|
||
### VS Code ### | ||
.vscode/ | ||
|
||
### Mac OS ### | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# 通过预签名机制在客户端实现OSS直传和下载 | ||
|
||
在典型的服务端和客户端架构下,常见的文件上传方式是服务端代理上传:客户端将文件上传到业务服务器,然后业务服务器将文件上传到OSS。在这个过程中,一份数据需要在网络上传输两次,会造成网络资源的浪费,增加服务端的资源开销。同时从OSS上传/下载文件需要使用RAM用户的访问密钥(AccessKey)来完成签名认证,但是在客户端中使用长期有效的访问密钥,可能会导致访问密钥泄露,进而引起安全问题。 | ||
|
||
本文档介绍了一种在客户端实现直接从OSS上传/下载文件的方案,避免了业务服务器中转文件,提高了上传速度,节省了服务器资源,同时,客户端基于预签名机制访问OSS,无需透露长期AccessKey,减少密钥泄露的风险。 | ||
|
||
这里针对本方案提供了相关代码示例,帮助您快速完成应用改造,减少开发和部署的复杂度。 | ||
|
||
|
||
## 使用步骤 | ||
|
||
### 目录结构说明 | ||
|
||
``` | ||
. | ||
└── code-example | ||
└── java | ||
└── spring-boot # Java SpringBoot示例代码 | ||
``` | ||
|
||
### Java示例代码 | ||
|
||
``` | ||
java/spring-boot/src/main | ||
├── java/org/example | ||
│ ├── Application.java | ||
│ ├── config | ||
│ │ ├── CredentialConfig.java # 初始化凭据客户端 | ||
│ │ └── OssConfig.java # 初始化OSS客户端等 | ||
│ ├── controller | ||
│ │ ├── DownloadController.java | ||
│ │ └── UploadController.java | ||
│ ├── model | ||
│ │ ├── OssPostCallback.java | ||
│ │ ├── PostCallbackResp.java | ||
│ │ └── PostSignatureResp.java | ||
│ └── service | ||
│ ├── DownloadService.java # 生成客户端可以直接下载的签名URL | ||
│ └── UploadService.java # 生成客户端直传的Post Policy和签名,并处理OSS回调逻辑 | ||
└── resources | ||
├── application.properties | ||
└── static # 前端示例 | ||
└── index.html | ||
``` | ||
|
||
#### 环境要求 | ||
|
||
该示例代码需要在ECS环境中执行,执行前,请确保运行环境中已配置好Java和Maven。 | ||
|
||
1. Java Development Kit (JDK):确保已安装Java 8或更高版本。 | ||
2. Apache Maven:确保已安装Maven 3.6.0或更高版本。 | ||
|
||
运行以下命令来检查Java安装: | ||
|
||
```bash | ||
java -version | ||
``` | ||
|
||
运行以下命令来检查Maven安装: | ||
|
||
```bash | ||
maven -version | ||
``` | ||
|
||
#### 本地运行 | ||
|
||
1. 首先您需要配置凭证信息,建议您通过环境变量进行配置: | ||
|
||
``` | ||
ALIBABA_CLOUD_ACCESS_KEY_ID=<您的AccessKey ID>;ALIBABA_CLOUD_ACCESS_KEY_SECRET=<您的AccessKey Secret> | ||
``` | ||
> 您也可以将该项目部署到阿里云上,强烈建议您使用临时凭证来代替固定AccessKey。 | ||
2. 接着您需要进行应用配置,打开 `resources/application.properties` 进行如下配置: | ||
``` | ||
# 服务启动端口个 | ||
server.port = 7001 | ||
# 地域,以杭州地域为例 | ||
region.id=cn-hangzhou | ||
# 请填写OSS Bucket名称,示例中会从该Bucket中上传下载文件 | ||
oss.bucket= | ||
# 当前服务的请求地址,OSS会通过该地址回调到当前服务 | ||
service.address= | ||
``` | ||
同时,在`resources/static/index.html`和`java/org/example/config/OssConfig.java`中配置对应的本地服务地址、OSS Bucket目录等信息。 | ||
3. 启动`Application.java`,浏览器打开`resources/static/index.html`体验Web端示例 |
80 changes: 80 additions & 0 deletions
80
solution/solution-oss-pre-signed/code-example/java/spring-boot/pom.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-parent</artifactId> | ||
<version>2.3.4.RELEASE</version> | ||
</parent> | ||
<groupId>org.example</groupId> | ||
<artifactId>spring-boot</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
<packaging>jar</packaging> | ||
|
||
<properties> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
<maven.compiler.source>1.8</maven.compiler.source> | ||
<maven.compiler.target>1.8</maven.compiler.target> | ||
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> | ||
<exec.cleanupDaemonThreads>false</exec.cleanupDaemonThreads> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-web</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-aop</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.projectlombok</groupId> | ||
<artifactId>lombok</artifactId> | ||
<version>1.18.6</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>com.alibaba.fastjson2</groupId> | ||
<artifactId>fastjson2</artifactId> | ||
<version>2.0.51</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>com.aliyun</groupId> | ||
<artifactId>tea</artifactId> | ||
<version>1.3.1</version> | ||
</dependency> | ||
|
||
<!-- oss-sdk --> | ||
<!-- Requires: version >= 3.17.4 --> | ||
<!-- 推荐使用最新版本 --> | ||
<dependency> | ||
<groupId>com.aliyun.oss</groupId> | ||
<artifactId>aliyun-sdk-oss</artifactId> | ||
<version>3.17.4</version> | ||
</dependency> | ||
|
||
<!-- Requires: version >= 0.3.4 --> | ||
<!-- 推荐使用最新版本 --> | ||
<!--获取所有已发布的版本列表,请参见https://github.com/aliyun/credentials-java/blob/master/ChangeLog.txt--> | ||
<dependency> | ||
<groupId>com.aliyun</groupId> | ||
<artifactId>credentials-java</artifactId> | ||
<version>0.3.5</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-maven-plugin</artifactId> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
11 changes: 11 additions & 0 deletions
11
...n-oss-pre-signed/code-example/java/spring-boot/src/main/java/org/example/Application.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package org.example; | ||
|
||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
|
||
@SpringBootApplication | ||
public class Application { | ||
public static void main(String[] args) { | ||
SpringApplication.run(Application.class, args); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
...gned/code-example/java/spring-boot/src/main/java/org/example/config/CredentialConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package org.example.config; | ||
|
||
import com.aliyun.credentials.Client; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
public class CredentialConfig { | ||
|
||
// 初始化凭据客户端,Credential SDK Client 应该是单例,不要每次请求都重新 new 一个,避免内存泄露 | ||
// 借助Credentials工具的默认凭据链,您可以用同一套代码,通过程序之外的配置来控制不同环境下的凭据获取方式 | ||
// 当您在初始化凭据客户端不传入任何参数时,Credentials工具将会尝试按照如下顺序查找相关凭据信息(优先级由高到低): | ||
// 1. 使用系统属性 | ||
// 2. 使用环境变量 | ||
// 3. 使用OIDC RAM角色 | ||
// 4. 使用配置文件 | ||
// 5. 使用ECS实例RAM角色(需要通过环境变量 ALIBABA_CLOUD_ECS_METADATA 指定 ECS 实例角色名称;通过环境变量 ALIBABA_CLOUD_ECS_IMDSV2_ENABLE=true 开启在加固模式下获取STS Token) | ||
// https://help.aliyun.com/zh/sdk/developer-reference/v2-manage-access-credentials#3ca299f04bw3c | ||
// 要使用默认凭据链,初始化 Client 时,必须使用空的构造函数,不能配置 Config 入参 | ||
@Bean | ||
Client getCredentialClient() { | ||
return new Client(); | ||
} | ||
|
||
// 除了使用上面的默认凭据链,您也可以在代码中显式配置,来初始化凭据客户端 | ||
// 如下所示,可以进行显式配置,以ECS实例角色为例 | ||
//@Bean | ||
//Client getCredentialClient() { | ||
// Config config = new Config() | ||
// .setType("ecs_ram_role") | ||
// // 选填,该ECS实例角色的角色名称,不填会自动获取,建议加上以减少请求次数 | ||
// .setRoleName("<请填写ECS实例角色的角色名称>") | ||
// // 在加固模式下获取STS Token,强烈建议开启 | ||
// .setEnableIMDSv2(true); | ||
// return new Client(config); | ||
//} | ||
} |
116 changes: 116 additions & 0 deletions
116
...-pre-signed/code-example/java/spring-boot/src/main/java/org/example/config/OssConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package org.example.config; | ||
|
||
import com.aliyun.credentials.models.CredentialModel; | ||
import com.aliyun.oss.ClientBuilderConfiguration; | ||
import com.aliyun.oss.OSS; | ||
import com.aliyun.oss.OSSClientBuilder; | ||
import com.aliyun.oss.common.auth.Credentials; | ||
import com.aliyun.oss.common.auth.CredentialsProvider; | ||
import com.aliyun.oss.common.auth.DefaultCredentials; | ||
import com.aliyun.oss.common.comm.SignVersion; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
import javax.annotation.PostConstruct; | ||
|
||
@Configuration | ||
public class OssConfig { | ||
|
||
@Value("${region.id}") | ||
String regionId; | ||
|
||
@Value("${oss.bucket}") | ||
String bucket; | ||
|
||
@Value("${service.address}") | ||
String serviceAddress; | ||
|
||
String dir = "example/"; | ||
|
||
String endpoint; | ||
|
||
String host; | ||
|
||
// 上传文件时,post policy 的过期时间,单位为毫秒 | ||
long uploadExpireTime = 3600; | ||
|
||
// 下载文件时,签名 url 的过期时间,单位为毫秒 | ||
long downloadExpireTime = 300; | ||
|
||
String postCallbackUrl; | ||
|
||
@Autowired | ||
com.aliyun.credentials.Client credentialClient; | ||
|
||
@PostConstruct | ||
public void init() { | ||
this.endpoint = "oss-" + regionId + ".aliyuncs.com"; | ||
this.host = "https://" + bucket + "." + endpoint; | ||
this.postCallbackUrl = serviceAddress + "/upload/callback"; | ||
} | ||
|
||
// 自定义 OSS Credentails Provider,通过该 Provder 初始化下方 OSS SDK Client | ||
// 该 Provdier 会从 Credentail SDK Client 中获取最新的 STS Token | ||
// Credentail SDK Client 会自动更新 STS Token,您无需关心 STS Token 到期如何更换的问题 | ||
@Bean | ||
CredentialsProvider getOssCredentialsProvider() { | ||
return new CredentialsProvider() { | ||
@Override | ||
public void setCredentials(Credentials credentials) { | ||
} | ||
|
||
@Override | ||
public Credentials getCredentials() { | ||
// 保证线程安全,从 CredentialModel 中获取 ak/sk/security token | ||
CredentialModel credentialModel = credentialClient.getCredential(); | ||
String ak = credentialModel.getAccessKeyId(); | ||
String sk = credentialModel.getAccessKeySecret(); | ||
String token = credentialModel.getSecurityToken(); | ||
return new DefaultCredentials(ak, sk, token); | ||
} | ||
}; | ||
} | ||
|
||
// 初始化阿里云 OSS SDK 客户端 | ||
// OSS SDK Client 建议是单例模式,不要每次请求都重新 New 一个,避免出现内存泄露的问题 | ||
@Bean | ||
OSS getOssClient(CredentialsProvider credentialsProvider) { | ||
// 建议使用更安全的V4签名算法,则初始化时需要加入endpoint对应的region信息,同时声明SignVersion.V4 | ||
// OSS Java SDK 3.17.4及以上版本支持V4签名。 | ||
ClientBuilderConfiguration configuration = new ClientBuilderConfiguration(); | ||
configuration.setSignatureVersion(SignVersion.V4); | ||
|
||
return OSSClientBuilder.create() | ||
.endpoint(endpoint) | ||
.credentialsProvider(credentialsProvider) | ||
.clientConfiguration(configuration) | ||
.region(regionId) | ||
.build(); | ||
} | ||
|
||
public String getBucket() { | ||
return bucket; | ||
} | ||
|
||
public String getHost() { | ||
return host; | ||
} | ||
|
||
public long getUploadExpireTime() { | ||
return uploadExpireTime; | ||
} | ||
|
||
public String getPostCallbackUrl() { | ||
return postCallbackUrl; | ||
} | ||
|
||
public String getDir() { | ||
return dir; | ||
} | ||
|
||
public long getDownloadExpireTime() { | ||
return downloadExpireTime; | ||
} | ||
} |
Oops, something went wrong.