当前位置: 首页 > article >正文

若依框架实战:如何优雅地实现静态资源权限校验(附完整代码)

若依框架静态资源权限校验实战指南在企业级应用开发中静态资源的安全访问控制是一个常见需求。无论是小程序图片资源管理还是企业内部文档权限控制都需要确保只有授权用户才能访问特定资源。本文将深入探讨如何在若依(RuoYi)框架中实现静态资源的精细化权限校验。1. 静态资源权限校验的核心思路传统的静态资源管理通常采用Nginx直接托管或对象存储服务如MinIO但这些方案往往缺乏细粒度的权限控制能力。若依框架基于Spring Security的权限体系为我们提供了更灵活的解决方案。核心实现原理将静态资源存放在项目resources/static目录下通过自定义Controller拦截资源请求在返回资源前进行权限校验使用Response输出流返回资源内容这种方案的优势在于无需额外中间件依赖与业务权限体系无缝集成可实现文件级别的访问控制便于扩展日志记录等附加功能2. 基础实现方案我们先来看一个基础的静态资源控制器实现RestController RequestMapping(/static) public class StaticResourcesController { Autowired private ResourceLoader resourceLoader; GetMapping(/img/{fileName}) public void getImage(PathVariable String fileName, HttpServletResponse response) throws IOException { // 1. 构建资源路径 Resource resource resourceLoader.getResource( classpath:static/img/ fileName); // 2. 检查资源是否存在 if (!resource.exists()) { response.sendError(HttpStatus.NOT_FOUND.value()); return; } // 3. 设置响应头 response.setContentType(MediaType.IMAGE_JPEG_VALUE); // 4. 输出资源内容 Files.copy(resource.getInputStream(), response.getOutputStream()); } }这个基础版本已经实现了静态图片的访问控制但缺乏关键的权限校验环节。接下来我们将逐步完善它。3. 集成若依权限体系若依框架的权限控制主要基于PreAuthorize注解和权限字符串。我们可以利用这一机制为静态资源添加权限控制。3.1 添加权限注解PreAuthorize(ss.hasPermi(system:resource:view)) GetMapping(/img/{fileName}) public void getImage(PathVariable String fileName, HttpServletResponse response) throws IOException { // 实现同上 }这里使用了若依提供的ss表达式它会调用PermissionService检查当前用户是否拥有system:resource:view权限。3.2 动态权限控制有时我们需要根据资源类型或路径动态控制权限。例如不同部门的用户只能访问本部门的图片资源GetMapping(/img/{dept}/{fileName}) public void getDeptImage(PathVariable String dept, PathVariable String fileName, HttpServletResponse response) throws IOException { // 检查用户是否有权访问该部门资源 if (!securityService.canAccessDept(dept)) { response.sendError(HttpStatus.FORBIDDEN.value()); return; } Resource resource resourceLoader.getResource( classpath:static/img/ dept / fileName); // 其余处理逻辑... }4. 性能优化方案直接通过Controller返回静态资源虽然灵活但在高并发场景下可能存在性能问题。以下是几种优化策略4.1 缓存控制GetMapping(/img/{fileName}) public void getImage(PathVariable String fileName, HttpServletResponse response, RequestHeader(value If-Modified-Since, required false) String ifModifiedSince) throws IOException { Resource resource resourceLoader.getResource(classpath:static/img/ fileName); // 设置缓存头 long lastModified resource.lastModified(); String eTag DigestUtils.md5Hex(fileName lastModified); response.setHeader(ETag, eTag); response.setHeader(Cache-Control, max-age3600); response.setDateHeader(Last-Modified, lastModified); // 检查缓存有效性 if (cacheIsValid(ifModifiedSince, eTag, request)) { response.setStatus(HttpStatus.NOT_MODIFIED.value()); return; } // 输出资源内容... }4.2 异步输出对于大文件可以使用异步输出减少内存占用GetMapping(/large/{fileName}) public void getLargeFile(PathVariable String fileName, HttpServletResponse response) throws IOException { Resource resource resourceLoader.getResource(classpath:static/large/ fileName); response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); response.setContentLengthLong(resource.contentLength()); try (InputStream is resource.getInputStream(); OutputStream os response.getOutputStream()) { byte[] buffer new byte[8192]; int bytesRead; while ((bytesRead is.read(buffer)) ! -1) { os.write(buffer, 0, bytesRead); } } }5. 完整实现方案结合上述思路我们来看一个完整的静态资源控制器实现RestController RequiredArgsConstructor RequestMapping(/static) public class StaticResourcesController { private final ResourceLoader resourceLoader; private final PermissionService permissionService; GetMapping(/img/{category}/{fileName:.}) public void getImage(PathVariable String category, PathVariable String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException { // 1. 权限校验 if (!permissionService.hasPermission(resource:view: category)) { response.sendError(HttpStatus.FORBIDDEN.value(), 无权访问该资源); return; } // 2. 获取资源 Resource resource resourceLoader.getResource( classpath:static/img/ category / fileName); if (!resource.exists()) { response.sendError(HttpStatus.NOT_FOUND.value()); return; } // 3. 设置响应头 String contentType getContentType(fileName); response.setContentType(contentType); // 4. 缓存控制 long lastModified resource.lastModified(); String eTag DigestUtils.md5Hex(fileName lastModified); response.setHeader(ETag, eTag); response.setDateHeader(Last-Modified, lastModified); String requestETag request.getHeader(If-None-Match); if (eTag.equals(requestETag)) { response.setStatus(HttpStatus.NOT_MODIFIED.value()); return; } // 5. 输出资源 try (InputStream is resource.getInputStream(); OutputStream os response.getOutputStream()) { StreamUtils.copy(is, os); } } private String getContentType(String fileName) { String extension StringUtils.substringAfterLast(fileName, .); switch (extension.toLowerCase()) { case png: return MediaType.IMAGE_PNG_VALUE; case jpg: case jpeg: return MediaType.IMAGE_JPEG_VALUE; case gif: return MediaType.IMAGE_GIF_VALUE; case pdf: return MediaType.APPLICATION_PDF_VALUE; default: return MediaType.APPLICATION_OCTET_STREAM_VALUE; } } }6. 前端集成方案前端访问受保护的静态资源时需要确保携带有效的认证信息。以下是Vue中的示例// 获取图片资源 function getProtectedImage(url) { return axios.get(url, { responseType: blob, headers: { Authorization: Bearer getToken() } }).then(response { return URL.createObjectURL(response.data); }); } // 在组件中使用 export default { data() { return { imageUrl: } }, mounted() { getProtectedImage(/static/img/products/123.jpg).then(url { this.imageUrl url; }); } }7. 高级应用场景7.1 动态水印添加可以在返回图片资源时动态添加用户专属水印GetMapping(/watermark/{fileName}) public void getImageWithWatermark(PathVariable String fileName, HttpServletResponse response) throws IOException { // 获取原始图片 Resource resource resourceLoader.getResource(classpath:static/img/ fileName); BufferedImage image ImageIO.read(resource.getInputStream()); // 添加水印 Graphics2D g image.createGraphics(); g.setColor(Color.RED); g.setFont(new Font(Arial, Font.BOLD, 30)); g.drawString(Confidential - SecurityUtils.getUsername(), 10, 30); g.dispose(); // 输出图片 response.setContentType(MediaType.IMAGE_JPEG_VALUE); ImageIO.write(image, jpg, response.getOutputStream()); }7.2 访问日志记录记录静态资源的访问情况便于后续审计GetMapping(/doc/{fileName}) public void getDocument(PathVariable String fileName, HttpServletResponse response) throws IOException { // 权限校验... // 记录访问日志 SysResourceAccessLog accessLog new SysResourceAccessLog(); accessLog.setResourceName(fileName); accessLog.setAccessUser(SecurityUtils.getUserId()); accessLog.setAccessTime(new Date()); accessLog.setAccessIp(IpUtils.getIpAddr()); resourceAccessLogService.save(accessLog); // 返回资源... }8. 安全增强措施为确保静态资源访问的安全性还需要考虑以下方面文件路径安全防止目录遍历攻击// 检查文件名是否包含路径遍历字符 if (fileName.contains(../) || fileName.contains(..\\)) { response.sendError(HttpStatus.BAD_REQUEST.value(), 非法文件名); return; }文件类型限制只允许访问特定类型的文件private static final SetString ALLOWED_EXTENSIONS Set.of(jpg, png, gif, pdf); String extension StringUtils.substringAfterLast(fileName, .); if (!ALLOWED_EXTENSIONS.contains(extension.toLowerCase())) { response.sendError(HttpStatus.FORBIDDEN.value(), 禁止的文件类型); return; }速率限制防止资源被过度请求RateLimiter(value 10, key #fileName) GetMapping(/img/{fileName}) public void getImage(PathVariable String fileName, HttpServletResponse response) throws IOException { // ... }通过以上方案我们可以在若依框架中构建一个既安全又高效的静态资源权限控制系统。这种方案特别适合需要细粒度权限控制的内部管理系统以及需要保护敏感资源的企业应用场景。

相关文章:

若依框架实战:如何优雅地实现静态资源权限校验(附完整代码)

若依框架静态资源权限校验实战指南 在企业级应用开发中,静态资源的安全访问控制是一个常见需求。无论是小程序图片资源管理,还是企业内部文档权限控制,都需要确保只有授权用户才能访问特定资源。本文将深入探讨如何在若依(RuoYi)框架中实现静…...

快马AI助力:十分钟用Python搭建免费股票行情网站原型

最近想验证一个股票行情网站的原型,但作为独立开发者,从零搭建前后端实在太耗时。尝试用PythonFlask快速实现,结合InsCode(快马)平台的AI辅助功能,居然十分钟就完成了基础框架。记录下关键实现思路: 数据获取层设计 选…...

从YOLOv8到RTDETR:如何将训练后的YOLO指标无缝转换为COCO格式

1. 为什么需要YOLO到COCO格式转换 当你用YOLOv8官方代码训练RTDETR模型时,会发现评估结果默认输出的是YOLO格式指标。但学术界和工业界普遍采用COCO评估标准,这就好比在中国用人民币交易,到了欧洲就得换成欧元。我在去年帮某无人机公司做目标…...

PyTorch实战:手把手教你实现MobileFaceNet人脸识别模型(附完整代码)

PyTorch实战:从零构建MobileFaceNet人脸识别系统 人脸识别技术正在从实验室走向日常生活,而MobileFaceNet作为轻量级模型的代表,在移动端和嵌入式设备上展现出惊人的潜力。今天我们将深入探讨如何用PyTorch实现这个高效的神经网络架构&#x…...

通过配置驱动前端页面的实现方法

通过配置驱动前端页面的实现方法 配置驱动开发(Configuration-Driven Development, CDD)是一种通过外部配置而非硬编码来控制应用行为的开发模式。在前端领域,这种模式可以显著提升页面灵活性和可维护性。以下是具体实现方案: 理解…...

AI报告文档审核助力生态数据可信化:IACheck提升生物多样性调查报告物种识别准确性

在生态环境保护逐渐走向精细化管理的背景下,生物多样性调查数据的重要性不断提升。从自然保护区评估到生态修复项目,从环境影响评价到长期生态监测,物种数据已成为支撑决策的重要基础。而在这些数据中,“物种识别的准确性”&#…...

SaaS的末日重构:AI Agent浪潮下的危机与新生

目录 前言 一、 市场恐慌的源头:“软件-PE”的死亡循环 二、 核心重构:AI 将如何改造企业级 SaaS? 2.1 交互层的降维打击:从“点界面”到“说意图” 2.2 流程层的动态重组:从“应用中心”到“工作流中心” 2.3 定…...

Qwen3.5-9B-AWQ-4bit部署指南:双卡RTX 4090-D镜像免配置快速上手

Qwen3.5-9B-AWQ-4bit部署指南:双卡RTX 4090-D镜像免配置快速上手 1. 模型概述 千问3.5-9B-AWQ-4bit是一个支持图像理解的多模态模型,能够结合上传图片与文字提示词,输出中文分析结果。这个量化版本特别适合处理以下任务: 图片主…...

5分钟掌握:PowerToys Image Resizer让图片批量处理效率提升10倍

5分钟掌握:PowerToys Image Resizer让图片批量处理效率提升10倍 【免费下载链接】PowerToys Microsoft PowerToys is a collection of utilities that supercharge productivity and customization on Windows 项目地址: https://gitcode.com/GitHub_Trending/po/…...

告别效率黑洞:AOSP构建降本增效实战!更有最新技术报告免费领!

近年来,AI模型训练与大型软件构建的复杂度持续攀升,企业级操作系统的多分支、多产品构建正成为工程团队的“效率黑洞”。在 Android 平台,AOSP 构建尤为突出:全量构建耗时长、增量改动触发大规模重建、CI 队列冗长、资源消耗高等问…...

2025届毕业生推荐的五大AI论文方案推荐榜单

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 普及时,人工智能生成的内容让文本展现出一种高度模式化的特性,这一情…...

【数字电路】从双稳态到触发器:时序逻辑的存储基石

1. 数字世界的记忆细胞:双稳态电路探秘 当你按下电脑电源键的瞬间,数十亿个微型存储单元开始工作,它们就像数字世界的记忆细胞,忠实地记录着每一个比特的信息。这一切的起点,正是我们今天要探讨的双稳态电路。想象一下…...

AI学习路线及建议

1.python快速入门(边用边学,建议3天) 2.人工智能必备数学的基础(边用边学,建议3天) 3.机器学习(找工作面试考点,临面试前晚一点刷) 数据分析:短期找工作 ML/D…...

TCT亚洲展|直击3D打印前沿盛宴,解锁增材制造新趋势

近日,2026 TCT亚洲展在上海国家会展中心圆满落幕,作为亚太地区规模最大、专业性最强的3D打印与增材制造行业盛会,本届展会汇聚全球550余家头部展商,集中呈现了从工业级设备、高性能材料到全场景应用方案的全产业链创新成果&#x…...

League Akari:英雄联盟玩家的终极智能工具箱 - 3大核心功能深度解析

League Akari:英雄联盟玩家的终极智能工具箱 - 3大核心功能深度解析 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power 🚀. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 还在为英雄联盟…...

终极指南:3步打造你的闲鱼AI客服机器人,实现24小时自动化值守

终极指南:3步打造你的闲鱼AI客服机器人,实现24小时自动化值守 【免费下载链接】XianyuAutoAgent 智能闲鱼客服机器人系统:专为闲鱼平台打造的AI值守解决方案,实现闲鱼平台724小时自动化值守,支持多专家协同决策、智能议…...

数字孪生+AI:某国家级技术科研机构:耦合仿真评估部件性能,长期运维监测承压状态

部件仿真|设备安全|能源装备|风险评估 某国家级技术科研机构长期服务于国家级重点工程与大型产业体系,在复杂系统运行保障、风险评估与技术支撑等方面承担着关键角色。其业务覆盖多类型基础设施与工程场景,具备完善的…...

【数值分析】线性方程组求解的MATLAB实战:从高斯消元到追赶法

1. 线性方程组求解的数值方法概述 在工程计算和科学研究中,线性方程组的求解是一个基础而重要的问题。想象一下,你正在设计一座桥梁,需要计算各个节点的受力情况;或者你在分析电路时,需要确定各个支路的电流大小。这些…...

SiameseAOE中文-base高性能部署:WebUI响应<800ms,吞吐达12QPS(RTX4090)

SiameseAOE中文-base高性能部署&#xff1a;WebUI响应<800ms&#xff0c;吞吐达12QPS&#xff08;RTX4090&#xff09; 今天要跟大家聊一个非常实用的工具——SiameseAOE通用属性观点抽取模型。你可能听说过信息抽取&#xff0c;但面对海量文本&#xff0c;如何快速、准确地…...

SpringBoot + MyBatis-Plus项目实战:从零搭建一个JavaEE课程设计骨架(附完整源码结构解析)

SpringBoot MyBatis-Plus项目实战&#xff1a;从零搭建一个JavaEE课程设计骨架&#xff08;附完整源码结构解析&#xff09; 当你第一次打开IDE准备开始JavaEE课程设计时&#xff0c;面对空白的项目窗口是否感到无从下手&#xff1f;本文将带你从零开始&#xff0c;用SpringBo…...

StructBERT文本相似度模型Java开发实战:SpringBoot集成与API调用

StructBERT文本相似度模型Java开发实战&#xff1a;SpringBoot集成与API调用 你是不是也遇到过这样的场景&#xff1f;用户搜索“苹果手机”&#xff0c;你希望系统不仅能返回iPhone&#xff0c;还能识别出“苹果公司手机”、“Apple iPhone”这些同义查询。或者&#xff0c;在…...

新手福音:在快马平台开启你的云端代码编程第一课

作为一名刚接触编程的新手&#xff0c;我最近发现了一个特别适合入门的学习方式——云端代码编程。以前总觉得学编程要先装一堆软件、配置环境&#xff0c;光是这些准备工作就能劝退不少人。但在InsCode(快马)平台上&#xff0c;这些烦恼都不存在了。 零门槛的编程初体验 打开平…...

牙科手术显微镜市场:其中中国市场占比超15%

在口腔诊疗向精细化、微创化演进的进程中&#xff0c;牙科手术显微镜作为核心光学放大设备&#xff0c;凭借其高照度、高景深与高清晰度特性&#xff0c;成为提升根管治疗、牙周手术及种植修复等环节精准性的关键工具。该设备集成连续变倍观察、同轴照明、术野调焦及影像记录系…...

用快马AI一键生成数据库管理原型,告别navicat手工建表写接口

用快马AI一键生成数据库管理原型&#xff0c;告别navicat手工建表写接口 最近在开发一个员工信息管理系统时&#xff0c;我深刻体会到传统数据库管理工具的局限性。虽然navicat这类工具能帮我们可视化操作数据库&#xff0c;但每次新建项目都要手动建表、写接口&#xff0c;重…...

开源吐槽大会:技术圈的幽默自省

开源项目吐槽大会技术文章大纲主题与目的开源项目吐槽大会旨在通过幽默、犀利的视角&#xff0c;揭示开源生态中的常见问题&#xff0c;促进开发者反思与改进。文章将从技术、社区、维护等角度展开&#xff0c;兼顾娱乐性与建设性。核心内容结构技术层面的经典槽点 依赖地狱&am…...

零基础入门gstack:借助快马AI生成你的第一个可运行React+TypeScript项目

作为一名刚接触前端开发的新手&#xff0c;第一次听说gstack&#xff08;ViteReactTypeScript组合&#xff09;时&#xff0c;我完全不知道从何入手。直到发现了InsCode(快马)平台&#xff0c;才真正体会到"零配置"开发是什么感觉。下面记录我的学习过程&#xff0c;…...

从零到一:在Trae平台构建网页数据智能抓取与分析引擎

1. 为什么你需要一个网页数据智能抓取引擎&#xff1f; 每次看到同事手动复制网页数据到Excel&#xff0c;我都忍不住想递杯咖啡——这活儿太费时了&#xff01;去年我帮市场部做竞品分析&#xff0c;发现他们每周要花8小时手工整理20个电商平台的价格数据。直到我们用Trae平台…...

AutoSAR从入门到精通:构建标准化汽车软件架构的完整指南

1. 为什么汽车软件需要AutoSAR&#xff1f; 十年前我刚入行汽车电子时&#xff0c;每个OEM厂商的ECU软件都是独立开发的"黑盒子"。同一款车窗控制功能&#xff0c;在德系、日系、美系车型上要用完全不同的代码实现。更痛苦的是&#xff0c;当需要升级ADAS功能时&…...

【深度剖析】从libgomp TLS内存分配冲突到scikit-learn在ARM平台的兼容性优化

1. ARM架构下TLS内存分配的底层原理 当你在ARM服务器上跑scikit-learn模型时&#xff0c;突然蹦出"cannot allocate memory in static TLS block"错误&#xff0c;这背后其实是线程本地存储&#xff08;TLS&#xff09;在作祟。想象每个线程都有自己专属的储物柜&…...

解决Python ssl模块与系统OpenSSL版本不一致的编译指南

1. 为什么Python的ssl模块会与系统OpenSSL版本不一致&#xff1f; 很多开发者都遇到过这样的困惑&#xff1a;明明系统已经升级了OpenSSL&#xff0c;为什么Python的ssl模块还在使用旧版本&#xff1f;这个问题其实源于Python的编译机制。Python在编译安装时&#xff0c;会将当…...