oss桶权限为私密时,列表查看时桶为私密的文件获取临时url(优化列表查看功能,添加下载功能)

This commit is contained in:
chenchen 2022-10-17 17:54:29 +08:00
parent 8665bffcff
commit a79fda4d05
8 changed files with 133 additions and 49 deletions

View File

@ -15,6 +15,8 @@ import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.file.FileUtils; import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.oss.core.OssClient;
import com.ruoyi.oss.factory.OssFactory;
import com.ruoyi.system.domain.SysOss; import com.ruoyi.system.domain.SysOss;
import com.ruoyi.system.domain.bo.SysOssBo; import com.ruoyi.system.domain.bo.SysOssBo;
import com.ruoyi.system.domain.vo.SysOssVo; import com.ruoyi.system.domain.vo.SysOssVo;
@ -96,23 +98,7 @@ public class SysOssController extends BaseController {
@SaCheckPermission("system:oss:download") @SaCheckPermission("system:oss:download")
@GetMapping("/download/{ossId}") @GetMapping("/download/{ossId}")
public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException { public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException {
SysOssVo sysOss = iSysOssService.getById(ossId); iSysOssService.download(ossId,response);
if (ObjectUtil.isNull(sysOss)) {
throw new ServiceException("文件数据不存在!");
}
FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName());
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
long data;
try {
data = HttpUtil.download(sysOss.getUrl(), response.getOutputStream(), false);
} catch (HttpException e) {
if (e.getMessage().contains("403")) {
throw new ServiceException("无读取权限, 请在对应的OSS开启'公有读'权限!");
} else {
throw new ServiceException(e.getMessage());
}
}
response.setContentLength(Convert.toInt(data));
} }
/** /**

View File

@ -10,11 +10,6 @@ import java.util.List;
*/ */
public interface OssConstant { public interface OssConstant {
/**
* OSS模块KEY
*/
String SYS_OSS_KEY = "sys_oss:";
/** /**
* 默认配置KEY * 默认配置KEY
*/ */

View File

@ -172,11 +172,10 @@ public class OssClient {
} }
public String getPrivateUrl(String objectKey, Integer second) { public String getPrivateUrl(String objectKey, Integer second) {
// objectKey = "file/2022/10/13/81eef51cb0734dedbfa616493a021fe4.jpg";
GeneratePresignedUrlRequest generatePresignedUrlRequest = GeneratePresignedUrlRequest generatePresignedUrlRequest =
new GeneratePresignedUrlRequest(properties.getBucketName(), objectKey) new GeneratePresignedUrlRequest(properties.getBucketName(), objectKey)
.withMethod(HttpMethod.GET) .withMethod(HttpMethod.GET)
.withExpiration(new Date(Instant.now().toEpochMilli() + 1000 * second)); .withExpiration(new Date(System.currentTimeMillis() + 1000 * second));
URL url = client.generatePresignedUrl(generatePresignedUrlRequest); URL url = client.generatePresignedUrl(generatePresignedUrlRequest);
return url.toString(); return url.toString();
} }

View File

@ -0,0 +1,35 @@
package com.ruoyi.oss.enumd;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 桶访问策略配置
*
* @author 陈賝
*/
@Getter
@AllArgsConstructor
public enum AccessPolicyType {
/**
* private
*/
PRIVATE("0"),
/**
* public
*/
PUBLIC("1"),
/**
* constum
*/
CONSTUM("2");
/**
* 类型
*/
private final String type;
}

View File

@ -7,6 +7,8 @@ import com.ruoyi.system.domain.bo.SysOssBo;
import com.ruoyi.system.domain.vo.SysOssVo; import com.ruoyi.system.domain.vo.SysOssVo;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -25,6 +27,8 @@ public interface ISysOssService {
SysOss upload(MultipartFile file); SysOss upload(MultipartFile file);
void download(Long ossId, HttpServletResponse response) throws IOException;
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
} }

View File

@ -1,6 +1,9 @@
package com.ruoyi.system.service.impl; package com.ruoyi.system.service.impl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -10,10 +13,13 @@ import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.JsonUtils; import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.redis.CacheUtils;
import com.ruoyi.common.utils.redis.RedisUtils; import com.ruoyi.common.utils.redis.RedisUtils;
import com.ruoyi.oss.constant.OssConstant; import com.ruoyi.oss.constant.OssConstant;
import com.ruoyi.oss.core.OssClient; import com.ruoyi.oss.core.OssClient;
import com.ruoyi.oss.entity.UploadResult; import com.ruoyi.oss.entity.UploadResult;
import com.ruoyi.oss.enumd.AccessPolicyType;
import com.ruoyi.oss.exception.OssException; import com.ruoyi.oss.exception.OssException;
import com.ruoyi.oss.factory.OssFactory; import com.ruoyi.oss.factory.OssFactory;
import com.ruoyi.oss.properties.OssProperties; import com.ruoyi.oss.properties.OssProperties;
@ -24,9 +30,11 @@ import com.ruoyi.system.mapper.SysOssMapper;
import com.ruoyi.system.service.ISysOssService; import com.ruoyi.system.service.ISysOssService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -49,19 +57,7 @@ public class SysOssServiceImpl implements ISysOssService {
public TableDataInfo<SysOssVo> queryPageList(SysOssBo bo, PageQuery pageQuery) { public TableDataInfo<SysOssVo> queryPageList(SysOssBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<SysOss> lqw = buildQueryWrapper(bo); LambdaQueryWrapper<SysOss> lqw = buildQueryWrapper(bo);
Page<SysOssVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); Page<SysOssVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
List<SysOssVo> filterResult = result.getRecords().stream().map(o -> { List<SysOssVo> filterResult = result.getRecords().stream().map(this::matchingUrl).collect(Collectors.toList());
Object json = RedisUtils.getCacheObject(OssConstant.SYS_OSS_KEY + o.getService());
OssProperties properties = JsonUtils.parseObject(json.toString(), OssProperties.class);
if (properties == null) {
throw new OssException("系统异常, '" + o.getService() + "'配置信息不存在!");
}
String privateFlag = "0";
if (properties.getAccessPolicy().equals(privateFlag)) {
OssClient storage = OssFactory.instance(o.getService());
o.setUrl(storage.getPrivateUrl(o.getFileName(), 100));
}
return o;
}).collect(Collectors.toList());
result.setRecords(filterResult); result.setRecords(filterResult);
return TableDataInfo.build(result); return TableDataInfo.build(result);
} }
@ -98,6 +94,27 @@ public class SysOssServiceImpl implements ISysOssService {
return baseMapper.selectVoById(ossId); return baseMapper.selectVoById(ossId);
} }
@Override
public void download(Long ossId, HttpServletResponse response) throws IOException {
SysOssVo sysOss = this.matchingUrl(this.getById(ossId));
if (ObjectUtil.isNull(sysOss)) {
throw new ServiceException("文件数据不存在!");
}
FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName());
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
long data;
try {
data = HttpUtil.download(sysOss.getUrl(), response.getOutputStream(), false);
} catch (HttpException e) {
if (e.getMessage().contains("403")) {
throw new ServiceException("无读取权限, 请在对应的OSS开启'公有读'权限!");
} else {
throw new ServiceException(e.getMessage());
}
}
response.setContentLength(Convert.toInt(data));
}
@Override @Override
public SysOss upload(MultipartFile file) { public SysOss upload(MultipartFile file) {
String originalfileName = file.getOriginalFilename(); String originalfileName = file.getOriginalFilename();
@ -133,4 +150,24 @@ public class SysOssServiceImpl implements ISysOssService {
return baseMapper.deleteBatchIds(ids) > 0; return baseMapper.deleteBatchIds(ids) > 0;
} }
/**
* 匹配Url
*
* @param oss OSS对象
* @return oss 匹配Url的OSS对象
*/
private SysOssVo matchingUrl(SysOssVo oss) {
OssProperties properties = JsonUtils.parseObject(
CacheUtils.get(CacheNames.SYS_OSS_CONFIG, oss.getService()).toString(),
OssProperties.class
);
if (properties == null) {
throw new OssException("系统异常, '" + oss.getService() + "'配置信息不存在!");
}
if (StringUtils.equals(AccessPolicyType.PRIVATE.getType(), properties.getAccessPolicy())) {
OssClient storage = OssFactory.instance(oss.getService());
oss.setUrl(storage.getPrivateUrl(oss.getFileName(), 100));
}
return oss;
}
} }

View File

@ -80,6 +80,7 @@
<el-table-column label="桶名称" align="center" prop="bucketName" /> <el-table-column label="桶名称" align="center" prop="bucketName" />
<el-table-column label="前缀" align="center" prop="prefix" /> <el-table-column label="前缀" align="center" prop="prefix" />
<el-table-column label="域" align="center" prop="region" /> <el-table-column label="域" align="center" prop="region" />
<el-table-column label="桶权限类型" align="center" prop="accessPolicy" :formatter = "accessPolicyStateFormat" />
<el-table-column label="状态" align="center" prop="status"> <el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope"> <template slot-scope="scope">
<el-switch <el-switch
@ -151,14 +152,11 @@
>{{dict.label}}</el-radio> >{{dict.label}}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="桶权限类型">
<el-form-item label="AccessPolicy">
<el-radio-group v-model="form.accessPolicy"> <el-radio-group v-model="form.accessPolicy">
<el-radio <el-radio label="0">private</el-radio>
v-for="dict in dict.type.access_policy" <el-radio label="1">public</el-radio>
:key="dict.value" <el-radio label="2">custom</el-radio>
:label="dict.value"
>{{dict.label}}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="域" prop="region"> <el-form-item label="域" prop="region">
@ -189,7 +187,7 @@ import {
export default { export default {
name: "OssConfig", name: "OssConfig",
dicts: ['sys_yes_no', 'sys_normal_disable','access_policy'], dicts: ['sys_yes_no', 'sys_normal_disable'],
data() { data() {
return { return {
// loading // loading
@ -218,6 +216,21 @@ export default {
isHttpsOptions: [], isHttpsOptions: [],
// (0 1) // (0 1)
statusOptions: [], statusOptions: [],
//
accessPolicyOptions: [
{
label: 'private',
value: 0
},
{
label: 'public',
value: 1
},
{
label: 'custom',
value: 2
}
],
// //
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
@ -392,6 +405,16 @@ export default {
}).catch(() => { }).catch(() => {
row.status = row.status === "0" ? "1" : "0"; row.status = row.status === "0" ? "1" : "0";
}) })
},
accessPolicyStateFormat(row) {
if (row.accessPolicy === "0") {
return <span class="el-tag el-tag--warning el-tag--medium el-tag--light" > private </span>
} else if (row.accessPolicy === "1") {
return <span class="el-tag el-tag--success el-tag--medium el-tag--light" > public </span>
} else if (row.accessPolicy === "2") {
return <span class="el-tag el-tag--medium el-tag--light" > constum </span>
}
} }
} }
}; };

View File

@ -31,9 +31,14 @@
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" /> <el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
<el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" /> <el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
<el-table-column label="状态" align="center" prop="status"> <el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope"> <!-- <template slot-scope="scope"> -->
<dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/> <div slot="status" slot-scope="text, record">
</template> <a v-if="record.status == 1" style="color: #000000d9">待审核</a>
<a v-if="record.status == 2" style="color: #000000d9">正常</a>
<a v-if="record.status == 3" style="color: #f36e48">已驳回</a>
<a v-if="record.status == 4" style="color: #000000d9">已禁用</a>
</div>
<!-- </template> -->
</el-table-column> </el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> <el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope"> <template slot-scope="scope">