阿里云 Oss 防刷实现

公司私有Oss服务满且需设权限,避免文件泄露。作者翻阅阿里云Oss权限文档,整合常用方法,包含文件增删、修改权限、获取签名等。经测试,上传文件设公共读可正常访问,修改权限后需签名才能访问,删除文件传全路径即可。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

最近公司的私有 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 文档即可,机械代码不做过多描述

在这里插入图片描述

<think>嗯,用户想知道如何设计和实现一个互联网招聘系统。首先,我得理清这个系统的核心模块和架构。根据之前提到的引用,网上招聘系统相比传统方式有优势,比如节省成本、提高效率[^1][^3]。所以设计时要考虑用户管理、职位发布、简历管理、搜索匹配、在线沟通这些基本功能模块。 然后技术选型方面,引用里提到了SSM框架(Spring+SpringMVC+MyBatis),还有JSP和Servlet[^2]。可能后端用Spring Boot简化配置,前端用Vue或React,数据库选MySQL。另外,需要考虑系统的可扩展性和安全性,比如使用JWT做认证,Redis缓存热点数据。 用户需求分析很重要,得区分求职者、企业和管理员的不同需求。求职者需要搜索职位、投递简历,企业要发布职位、查看简历,管理员则管理用户和内容。这里可能需要角色权限控制,Spring Security可能是个不错的选择。 数据库设计方面,用户表、企业表、职位表、简历表、投递记录表这些是必须的。比如职位表要包含职位名称、类型、薪资、要求等字段,简历表需要关联用户,存储教育经历和工作经验。 在实现方案里,前后端分离的架构比较流行,前端用Vue+Element UI,后端用Spring Boot整合MyBatis。第三方服务集成比如阿里云的短信服务,用于注册和通知,可能还需要用到Elasticsearch实现高效搜索。 性能优化方面,缓存和负载均衡是关键。引用提到传统系统需要很多人力,而线上系统可以节省资源,所以系统需要稳定,能处理高并发。可能用Nginx做反向代理,Redis缓存高频访问的数据。 测试和部署阶段,单元测试、压力测试不能少,自动化部署用Jenkins或Docker容器化,提高效率。安全方面,止SQL注入和XSS攻击,HTTPS加密数据传输。 最后,系统上线后要持续收集反馈,优化用户体验。比如简历解析的准确度,推荐算法的精准性,这些都需要不断迭代。可能还需要考虑移动端适配,或者开发小程序,增加用户粘性。</think>### 互联网招聘系统设计与实现方案 #### 一、系统架构设计 1. **分层架构** 采用前后端分离模式,前端使用Vue.js+Element UI框架,后端基于Spring Boot+MyBatis构建,数据库使用MySQL,辅以Redis缓存高频数据[^4]。 2. **核心模块划分** - 用户模块:支持个人/企业双角色注册登录(含短信验证) - 职位模块:企业发布/管理岗位,支持分类筛选与薪资区间设置 - 简历模块:在线简历编辑、智能解析、PDF导出 - 搜索模块:Elasticsearch实现职位/简历双向精准检索 - 推荐模块:基于用户行为的协同过滤推荐算法 - 沟通模块:站内信+WebSocket实时聊天 #### 二、关键技术实现 ```java // 简历解析核心代码示例(使用Apache POI) public Resume parseResume(MultipartFile file) { try (InputStream is = file.getInputStream()) { XWPFDocument doc = new XWPFDocument(is); return extractResumeData(doc); // 提取文本段落与表格数据 } catch (IOException e) { throw new ResumeParseException("简历解析失败"); } } ``` #### 三、数据库设计要点 $$ \begin{array}{|c|c|} \hline \text{表名} & \text{核心字段} \\ \hline user & id, phone, password, type(1个人/2企业) \\ \hline position & id, company_id, title, salary_range \\ \hline resume & user_id, education_json, work_experience_json \\ \hline delivery & position_id, resume_id, status(0待处理/1已查看) \\ \hline \end{array} $$ #### 四、性能优化策略 1. 使用Redis缓存热门职位搜索数据,降低数据库压力 2. 采用Nginx负载均衡应对高并发场景 3. 简历文件存储采用OSS对象存储服务 4. 异步处理简历解析与消息推送任务 #### 五、安全护措施 - JWT令牌实现无状态认证 - 敏感数据加密存储(如密码采用BCrypt加密) - 接口机制(滑动窗口限流算法) - XSS过滤器净化用户输入内容
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小咸鱼的技术窝

你的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值