您在哪里进行验证?模型、控制器或视图
-
02-07-2019 - |
题
在 Web 表单应用程序中,您将用户输入验证放在哪里?
- 看法:JavaScript 客户端
- 控制器:服务器端语言(C#...)
- 模型:数据库(存储过程或依赖项)
我认为每个级别都需要验证:
- 用户是否输入了合理的值
- 日期是实际日期,数字是实际数字...
- 执行 1 中的所有检查。再次加上检查恶意攻击(IE XSS 或 SQL 注入)
- 1中完成的检查。主要是为了避免用户出错时服务器往返。
- 由于它们是在客户端用 JavaScript 完成的,因此您不能相信它们已经运行。再次验证这些值将阻止一些恶意攻击。
- 是否满足依赖关系(即用户是否对有效问题添加了评论)
- 良好的界面使得这些很难被违反。如果这里有什么东西被抓到,那就说明出了什么问题。
[灵感来自 这个回应]
解决方案
我检查了所有层,但我想指出我使用的验证技巧。
我在数据库层进行验证,对模型的适当约束将提供自动数据完整性验证。
对于大多数网络程序员来说,这似乎是一门艺术。
其他提示
模型中的验证,可选的 UI 中的自动化例程,从模型中获取提示并改善用户体验。
通过自动化例程,我的意思是用户界面中不应该有任何针对每个模型的验证代码。如果您有一个验证方法库,例如 RoR 的(具有 validates_presence_of :username 之类的方法),控制器或视图应该能够读取这些方法并应用等效的 javascript(或任何方便的)方法。
这意味着您必须在用户界面中复制完整的验证库,或者如果您使用预先存在的验证库,则至少提供一个映射。但是一旦完成,您就不必在模型外部编写任何验证逻辑。
验证可以在所有层进行。
验证来自 Web 表单的输入(所有字符串、转换为正确的类型等)与验证来自 Web 服务或 XML 文件等的输入不同。每个都有其自己的特殊情况。当然,您可以创建一个 Validator 辅助类,从而外部化 Validation 并允许它被视图共享。
然后进行 DAO 层验证 - 模型中是否有足够的数据可以持久保存(以满足非空约束等)等等。您甚至可以在数据库中检查约束(状态为('N','A','S','D')等)。
这很有趣。在最长的时间里,我在模型中执行了所有验证,就在我认为的 DAL(数据访问层)之上。我的模型通常按照表数据网关进行模式化,并使用提供抽象和低级 API 的 DAL。
在 TDG 内部,我将实现业务逻辑和验证,例如:
- 用户名是否为空
- 用户名 > 30 个字符
- 如果记录不存在,则返回错误
随着我的应用程序变得越来越复杂,我开始意识到大部分验证可以使用 JavaScript 在客户端完成。所以我将大部分验证逻辑重构为 JS 并清理了我的模型。
然后我意识到服务器端验证(不是过滤/转义——我认为不同)也应该在服务器中完成,并且只在客户端完成,作为锦上添花。
因此,当我再次意识到输入验证/断言和业务规则/逻辑之间可能存在明显差异时,验证逻辑又回来了。
基本上,如果它可以在应用程序的客户端(使用 JS)完成,我认为这是输入验证...如果它必须由模型完成(此记录是否已经存在,等等?)那么我会认为商业逻辑。令人困惑的是它们都保护数据模型的完整性。
如果您不验证用户名的长度,那么如何阻止人们创建单字符用户名呢?
我还没有完全决定下一步将该逻辑放在哪里,我认为这实际上取决于您更喜欢什么,薄控制器,重型模型,反之亦然......
在我的例子中,控制器往往更加以应用程序为中心,而模型如果精心制作,我通常可以在“其他”项目中重用,而不仅仅是在内部,所以我更喜欢保持模型轻量级,而控制器则在较重的一侧。
推动你朝任一方向发展的力量实际上是个人观点、要求、经验等……
有趣的话题:)
验证 必须 在控制器中完成 - 这是确保安全和响应的唯一地方。
验证 应该 在视图中完成 - 它是联系点,将提供最佳的 UE 并节省服务器的额外工作。
验证 将要 在模型上完成 - 但仅限于特定核心级别的检查。数据库应该始终反映适当的约束,但让它代表真正的验证是低效的,而且数据库也不总是可以通过简单的约束来确定有效的输入。
所有验证都应该至少发生一次,并且应该在中间层进行,无论是在值对象中(在 DDD 意义上,不要与 DTO 混淆),还是通过实体本身的业务对象。可以进行客户端验证以增强用户体验。我倾向于不进行客户端验证,因为我可以立即暴露表单上的所有错误,但这只是我个人的偏好。数据库验证可以确保数据完整性,以防您搞砸了逻辑中间层或后端的东西。
我只在视图和控制器中执行此操作,数据库通过您的数据类型等强制执行其中的一些操作,但我希望在没有捕获错误的情况下不要走那么远。
不过,您几乎回答了自己的问题,重要的是要知道,您永远不能信任该视图,尽管这是向用户提供反馈的最简单途径,因此您需要至少在一个层面上进行清理。
嗯嗯,不确定。在我阅读这篇文章之前,我会说控制器:瘦控制器,胖模型
由于大多数验证取决于 商业规则, ,我对 业务层 作为第三方工具类。还有其他类型的验证,例如用户输入,虽然需要在控制器中进行,但您也可以将这些验证规则封装在第三方类中。实际上,这取决于要验证的内容。
客户端验证是次要的,只是为了构建一个轻量级的 输入验证, ,但是服务器端验证是 总是需要. 。你永远不能相信用户输入;)
。网 有很好的控制来构建验证,但是 业务层 总是需要更好的方法来验证数据,而这些控制不足以完成该任务。
视图中的简单输入验证。模型中的全面验证。原因?如果您更改视图技术,并且验证位于视图/控制器中,则必须为新视图重写验证。这可能会引入错误。将其放入模型中,所有视图都会重用......
但是,正如我所说,在视图中进行简单验证可以提高速度和简便性。