Strapi v4中如何对uploads文件夹及媒体资源做最高权限验证?
Strapi v4 媒体资源权限验证与uploads文件夹访问认证方案
1. 配置内置媒体库基础权限
先通过Strapi自带的角色权限系统,给不同用户组分配媒体资源的访问权限:
- 进入Strapi后台 → Settings → Roles & Permissions
- 针对目标角色(如
Authenticated),找到Media Library权限组:- 勾选
find、findOne权限以允许查看媒体资源 - 根据业务需求勾选
create、update、delete权限
- 勾选
- 若需更细粒度控制(比如仅允许用户访问自己上传的媒体),可自定义权限策略:
创建src/policies/own-media.js:
之后在角色权限设置中,为module.exports = async (policyContext, config, { strapi }) => { const { user } = policyContext.state; if (!user) return false; const media = await strapi.db.query('plugin::upload.file').findOne({ where: { id: policyContext.params.id }, populate: ['createdBy'] }); return media.createdBy.id === user.id; };Media Library的对应操作绑定该策略。
2. 自定义中间件拦截uploads直接访问
默认Strapi会直接托管public/uploads文件夹,未授权用户可通过URL直接访问。需编写中间件拦截这类请求并验证身份:
- 创建中间件文件
src/middlewares/auth-media.js:
module.exports = (config, { strapi }) => { return async (ctx, next) => { // 拦截/uploads路径请求,排除后台管理预览 if (ctx.path.startsWith('/uploads') && !ctx.path.startsWith('/admin')) { // 验证用户身份 const user = ctx.state.user; if (!user) { ctx.status = 403; ctx.body = { error: 'Unauthorized access to media' }; return; } // 可选:验证用户是否有权限访问该文件 const filePath = ctx.path.replace('/uploads/', ''); const media = await strapi.db.query('plugin::upload.file').findOne({ where: { url: `/uploads/${filePath}` }, populate: ['createdBy'] }); if (!media || media.createdBy.id !== user.id) { ctx.status = 403; ctx.body = { error: 'You do not have permission to access this media' }; return; } } await next(); }; };
- 修改
config/middlewares.js,注册中间件并调整静态文件托管规则:
module.exports = [ 'strapi::errors', './src/middlewares/auth-media', // 放在static中间件之前 { name: 'strapi::static', config: { exclude: ['/uploads/**'], // 让自定义中间件处理uploads路径 }, }, 'strapi::security', 'strapi::cors', 'strapi::poweredBy', 'strapi::logger', 'strapi::query', 'strapi::body', 'strapi::session', 'strapi::favicon', 'strapi::public', ];
3. 自定义媒体存储路径(可选)
如果需要更严格的用户隔离,可修改媒体存储路径,将用户ID作为路径一部分:
在config/plugins.js中配置upload插件:
module.exports = ({ env }) => ({ upload: { config: { provider: 'local', providerOptions: { generateFilename: (file) => { const userId = file?.related?.createdBy?.id || 'anonymous'; return `${userId}/${Date.now()}-${file.name}`; }, }, }, }, });
此时中间件可直接通过路径中的用户ID与当前登录用户ID对比,简化权限验证逻辑。
4. 关键注意事项
- 后台管理的媒体预览需排除拦截,中间件中已通过
!ctx.path.startsWith('/admin')处理 - 为避免浏览器缓存未授权资源,可在中间件添加响应头:
ctx.set('Cache-Control', 'no-cache, no-store, must-revalidate') - 测试需覆盖:未登录用户访问/uploads文件返回403,登录用户仅能访问自身上传的文件
内容的提问来源于stack exchange,提问作者Mu'aaz Joosuf
相关产品推荐
相关产品推荐

