前言
最近公司的私有 Oss 服务满了,且 Oss 地址需要设置权限,只有当前系统的登录用户才能访问 Oss 下载地址。一开始想着用 Nginx 做个转发来着,Nginx 每当检测当前请求包含特定的 Oss 地址就转发到我们的统一鉴权接口上去,但是紧接着又细想了一下,转发后的地址被恶意分享出去了,不也还是存在文件泄露的风险吗?于是又去翻阅了一下阿里云的 Oss 权限相关的文档。借此整合一些常用的方法,机械代码自留也是分享给大家
完整代码
里面整合了文件的增、删、修改权限、获取签名等方法,各位替换成各自的 ak、sk 即可
package com.queyi.qykgjx.util;
import com.aliyun.oss.*;
import com.aliyun.oss.internal.OSSHeaders;
import com.aliyun.oss.model.*;
import org.apache.http.ParseException;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class OssUtilCsdn {
private final static String ENDPOINT = "端点";
private final static String ACCESS_KEY_ID = "ak";
private final static String ACCESS_KEY_SECRET = "sk";
private final static String BUCKET_NAME = "容器名";
private static String HTTPS_URL_PREFIX = ENDPOINT.replace("https://", ("https://" + BUCKET_NAME + "."));
private final static String FILE_CATALOG = "文件上传目录";
public static void cpoy(String sourceKey, String dstKey, Boolean deleteSourceFile) {
OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
CopyObjectRequest copyObjectRequest = new CopyObjectRequest(BUCKET_NAME, sourceKey, BUCKET_NAME, dstKey);
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setObjectAcl(CannedAccessControlList.Private);
copyObjectRequest.setNewObjectMetadata(objectMetadata);
ossClient.copyObject(copyObjectRequest);
//删除被拷贝的文件
if (deleteSourceFile) ossClient.deleteObject(BUCKET_NAME, sourceKey);
ossClient.shutdown();
}
public static void setAcl(String bucketName, String url, Boolean privateAcl) {
ClientBuilderConfiguration config = new ClientBuilderConfiguration();
config.setSupportCname(false);
OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
try {
ossClient.setObjectAcl(bucketName == null ? BUCKET_NAME : bucketName,
getObjectNameByFullUrl(url),
privateAcl ? CannedAccessControlList.Private : CannedAccessControlList.PublicRead);
} catch (OSSException oe) {
oe.printStackTrace();
} catch (ClientException ce) {
ce.printStackTrace();
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
/**
* @param bucketName 容器名称
* @param file 待上传的文件
* @param acl 文件权限
*/
public static String upload(String bucketName, MultipartFile file, String acl) throws IOException {
OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
if (null == bucketName || bucketName.length() > 0) bucketName = BUCKET_NAME;
InputStream inputStream = file.getInputStream();
String filename = file.getOriginalFilename();
String[] split = filename.split("\\.");
filename = new Date().getTime() + "." + split[split.length - 1];
String s = FILE_CATALOG + "/" + filename.replaceAll("/", "");
PutObjectRequest o = new PutObjectRequest(bucketName, s, inputStream);
ObjectMetadata metadata = new ObjectMetadata();
metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
if ("private".equals(acl)) metadata.setObjectAcl(CannedAccessControlList.Private);
else if ("public".equals(acl)) metadata.setObjectAcl(CannedAccessControlList.PublicRead);
else metadata.setObjectAcl(CannedAccessControlList.Private);
o.setMetadata(metadata);
ossClient.putObject(o);
ossClient.shutdown();
inputStream.close();
return HTTPS_URL_PREFIX + "/" + s;
}
/**
* 获取签名
*/
public static String getSign(String key, int timeOut) throws ParseException {
ClientBuilderConfiguration config = new ClientBuilderConfiguration();
config.setSupportCname(false);
Date expiration = new Date(new Date().getTime() + timeOut * 1000L);
OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET, config);
URL url = ossClient.generatePresignedUrl(BUCKET_NAME, key, expiration);
return url.toString().split("\\?")[1];
}
public static String getAclPath(String url, int timeOut) throws ParseException {
ClientBuilderConfiguration config = new ClientBuilderConfiguration();
config.setSupportCname(false);
Date expiration = new Date(new Date().getTime() + timeOut * 1000L);
OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET, config);
return ossClient.generatePresignedUrl(BUCKET_NAME, getObjectNameByFullUrl(url), expiration).toString();
}
public static String getObjectNameByFullUrl(String url) {
if (!url.contains(FILE_CATALOG)) return null;
/**
* a/a.pdf
*/
return FILE_CATALOG + url.split(FILE_CATALOG)[1];
}
/**
* 删
*/
public static List<String> deleteObject(String bucketName, List<String> keys) {
ArrayList<String> newKeys = new ArrayList<>();
keys.stream().forEach(key -> {
newKeys.add(key.replace(HTTPS_URL_PREFIX + "/", ""));
});
OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
DeleteObjectsResult deleteObjectsResult = ossClient
.deleteObjects(new DeleteObjectsRequest(bucketName == null ? BUCKET_NAME : bucketName)
.withKeys(newKeys));
List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
ossClient.shutdown();
return deletedObjects;
}
}
整合接口
@PostMapping("csdnUpFile")
public Result csdnUpFile(@RequestParam("file") MultipartFile multipartFile
, @RequestParam("acl") String perm) throws IOException {
HashMap<String, String> map = new HashMap<>();
map.put("fileName", multipartFile.getOriginalFilename());
map.put("fileUrl", OssUtil.zzhUpload(null, multipartFile, perm));
return Result.success(map);
}
@PostMapping("csdnSetAcl")
public Result csdnSetAcl(@RequestParam("filePath") String filePath) throws IOException {
OssUtil.setAcl(null, filePath, true);
return Result.success("ok");
}
@PostMapping("csdnGetAclPath")
public Result csdnGetAclPath(@RequestParam("filePath") String url) throws IOException {
return Result.success(OssUtil.getAclPath(url, 60));
}
@PostMapping("csdnDeleteFile")
public Result csdnDeleteDile(@RequestBody List<String> urls) throws IOException {
return Result.success(OssUtil.deleteObject(null, urls));
}
测试
上传文件设置成公共读
文件正常访问
将全路径地址作为参数掉修改权限接口
再次访问此地址提示无权限
加上签名访问文件可以正常访问
其他方法不做一一测试了,删除文件也是传上传接口返回的全路径即可,可直接删除文件。其他操作看下阿里的Oss 文档即可,机械代码不做过多描述