知识卡片

数据验证不应按分层归属而应绑定到Bean本身

普通读书笔记卡

内容

数据验证常被排除在”安全”话题之外,但从概率上看,数据验证不严谨导致的 问题比黑客攻击导致的问题要常见得多,从风险上看也未必更小。”验证到底该 放在哪一层”这个问题——控制器层做/服务层做/两层都做/持久层做——本身就 问错了方向:只做格式校验会漏掉业务校验,两层都做会导致同一份校验逻辑 重复执行、甚至像段子里那样让用户在各层报错间反复”挤牙膏”式提交。更好 的做法是把校验行为从”哪一层执行”这个分层视角剥离出来,直接绑定到数据 对象(Bean)本身——Java Bean Validation正是这一思路的标准化实现。把 校验挂在Bean上有几个好处:无业务含义的格式校验(非空、长度、正则)可以 预置在类定义里、自动运行;有业务含义的校验(如”用户名邮箱手机号不能与 已有用户重复”)可以做成自定义约束注解,被多个方法、多个分层复用而不必 重复编写;可以统一管理异常体系、国际化、返回格式;还能避免”防御性判断” 污染业务代码本身。需要注意的是,无业务含义的校验不依赖外部资源、重复 执行没有成本,可以直接放在类定义里自动触发;带业务逻辑的校验往往要 查数据库等外部资源,重复执行可能有副作用,应该放在类定义之外、由调用方 显式声明何时触发,还可以用分组校验应对”新增要全校验、修改要跳过某字段” 这类非典型场景。

参考来源

- 位置:《凤凰架构:构建可靠的大型分布式系统》第5章"架构安全性" 5.6节"验证"(源文件:_epub-src对应OEBPS/Text/chapter74.xhtml) - 结论依据:原文用前端-控制器-安全-服务层-持久层依次抛异常的段子说明 分层校验的问题,进而提出把校验行为剥离出分层、绑定到Bean上的Java Bean Validation方案,并区分格式校验(预置在类定义内自动运行)与业务校验 (放在类定义外显式触发)两种用法,直接支撑本卡片结论。 - 原始内容:笔者提倡的做法是把校验行为从分层中剥离出来,不是在哪一层做, 而是在Bean上做,即Java Bean Validation……对于无业务含义的格式验证, 可以做到预置……对于有业务含义的业务验证,可以做到重用。