如何在Strapi v4.15.5端点仅返回认证用户所属条目?
问题场景与需求
场景
Strapi数据库中,默认的User集合类型与多个其他集合类型的条目存在关联关系,以此指定数据归属。
需求
请求接口时携带JWT Token作为Bearer认证,让接口仅返回该Token对应的认证用户所关联的数据。
环境
- Strapi版本:v4.15.5
- Node.js版本:v18.13.0
前端过滤数据的安全风险
- 权限绕过风险:前端只是在客户端做数据筛选,但后端仍会返回所有符合接口基础权限的数据。攻击者可直接调用后端接口,完全绕过前端逻辑获取不属于自己的所有数据。
- 数据泄露风险:即便前端不展示非用户数据,响应包中仍包含完整数据集,通过浏览器开发者工具或抓包工具就能轻松获取其他用户的敏感信息。
- 扩展维护隐患:后续新增集合类型时,每个前端请求都要手动添加用户ID过滤逻辑,极易遗漏,引发安全漏洞。
Strapi后端实现方案
核心逻辑是在后端自动注入当前认证用户的关联条件,确保接口仅返回用户所属数据,以下是具体实现步骤:
步骤1:确认认证机制生效
Strapi默认的JWT认证中间件会自动解析请求头中的Bearer Token,将认证后的用户信息挂载到ctx.state.user上。若请求未携带有效Token,接口会直接返回401未授权状态。
步骤2:自定义集合控制器(单集合)
以关联集合Article为例,重写其查询控制器添加用户过滤:
- 进入项目目录下的
src/api/article/controllers/article.js(无则创建) - 编写控制器代码:
'use strict'; module.exports = { // 重写列表查询接口 async find(ctx) { const user = ctx.state.user; if (!user) { return ctx.unauthorized('未提供有效认证信息'); } // 注入用户关联过滤条件,`user`为集合中关联User字段的名称,需根据实际修改 ctx.query.filters = { ...ctx.query.filters, user: { id: user.id } }; // 调用Strapi默认查询逻辑 return await super.find(ctx); }, // 重写单条数据查询接口 async findOne(ctx) { const user = ctx.state.user; if (!user) { return ctx.unauthorized('未提供有效认证信息'); } // 查询目标条目并关联用户信息 const entry = await strapi.db.query('api::article.article').findOne({ where: { id: ctx.params.id }, populate: ['user'] }); // 验证数据归属 if (!entry || entry.user.id !== user.id) { return ctx.forbidden('无权访问该数据'); } return entry; } };
步骤3:配置后台权限
在Strapi后台设置→角色与权限中,确保Authenticated角色拥有目标集合的find和findOne权限,同时关闭这两个权限的「公共访问」选项,仅允许认证用户访问。
步骤4:全局中间件批量处理(多集合)
若多个集合需统一过滤,可创建全局中间件:
- 创建
src/middlewares/filter-user-data.js文件:
'use strict'; module.exports = (config, { strapi }) => { return async (ctx, next) => { // 仅处理认证用户的GET类型集合查询请求 if (ctx.state.user && ctx.method === 'GET' && ctx.path.startsWith('/api/')) { const collectionName = ctx.path.split('/')[2]; // 定义需要过滤的集合列表 const targetCollections = ['articles', 'comments', 'orders']; if (targetCollections.includes(collectionName)) { // 注入用户过滤条件 ctx.query.filters = { ...ctx.query.filters, user: { id: ctx.state.user.id } }; } } await next(); }; };
- 在
config/middlewares.js中注册该中间件:
module.exports = [ 'strapi::errors', 'strapi::security', 'strapi::cors', 'strapi::poweredBy', 'strapi::logger', 'strapi::query', 'strapi::body', 'strapi::session', 'strapi::favicon', 'strapi::public', 'global::filter-user-data' // 添加此行注册中间件 ];
验证测试
- 获取用户Token:调用
/api/auth/local接口,传入用户名密码获取JWT Token。 - 携带Token请求接口:在请求头中添加
Authorization: Bearer <你的Token>,调用目标集合接口(如/api/articles)。 - 验证数据归属:确认返回数据仅属于当前用户,用其他用户Token测试时应无法获取非自身数据。
内容的提问来源于stack exchange,提问作者Ali Hosseini
相关产品推荐
相关产品推荐

