API任务创建:用户与项目同属企业验证及实体ID选型疑问
核心结论:必须验证Project与登录User同属一个Company
这是保障数据隔离和权限安全的必要操作,不能省略,下面分点说明原因、优化方案以及GUID方案的问题:
一、为什么必须做归属验证?
- 数据隔离的底线要求:不同Company的业务数据是完全隔离的,用户只能操作自己所属公司的资源。如果跳过这个验证,一旦传入错误或恶意的
projectId,会直接导致Task被创建到其他公司的Project中,造成数据错乱甚至泄露,这是严重的权限漏洞。 - 覆盖误操作与恶意请求:不管是前端传参错误、用户误操作,还是恶意构造请求,这个验证都能拦截非法操作,保证数据的归属正确性。
二、如何减少验证的代码与查询开销?
不用因为担心开销就放弃验证,通过以下方式可以有效优化:
- 封装通用校验逻辑:把「验证资源是否属于用户所在公司」的逻辑封装成通用函数或中间件,比如:
所有类似场景(如创建Project下的其他实体、修改Project等)直接调用这个方法,避免重复写代码。// 示例伪代码 public boolean isResourceBelongsToUserCompany(long resourceId, String resourceType, long userId) { // 根据资源类型查询对应表,关联用户所属公司完成校验 // 比如Project场景:查询Project的companyId是否等于用户的companyId } - 优化查询效率:
- 用单条JOIN查询完成校验:比如查询Project时直接关联User与Company的关系,一次SQL就能确认
Project.companyId = User.companyId,无需多次查询。 - 缓存用户所属CompanyId:把用户的CompanyId存入JWT Token(登录时返回)或Redis缓存,校验时只需查询Project的CompanyId,再和缓存的用户CompanyId对比,减少关联查询的开销。
- 添加数据库索引:给Project表的
companyId字段、User与Company关联表的对应字段添加索引,大幅提升查询速度。
- 用单条JOIN查询完成校验:比如查询Project时直接关联User与Company的关系,一次SQL就能确认
三、改用GUID作为实体Id,仅校验Project是否存在不可行
GUID只是让Id更难被猜测,但无法解决权限归属问题:
- 就算用GUID,用户仍可能通过泄露的测试数据、接口漏洞等方式获取其他公司的Project GUID,此时仅校验Project是否存在,依然会导致Task被创建到其他公司的资源中,权限漏洞依然存在。
- Id类型和数据归属没有关联,不管是int64还是GUID,都需要验证资源是否属于用户所在的Company,这一步无法跳过。
内容的提问来源于stack exchange,提问作者mmgyyc
相关产品推荐
相关产品推荐

