在哪里验证发送到 API 的参数?

Posted

技术标签:

【中文标题】在哪里验证发送到 API 的参数?【英文标题】:Where to validate parameters sent to an API? 【发布时间】:2021-12-08 00:55:10 【问题描述】:

在 API 设计中验证用户发送的参数的最佳做法是在哪个位置?通过参数验证,我指的是:检查所需的参数是否已发送,确保它们具有正确的格式等等......这里有几个简单的示例来验证 id 已发送。就是Python用Flask来说明:

A) 在控制器内的路由定义中添加验证逻辑。

@api.route('/job', methods=['GET'])
def get_jobs():
    try:
        if params["id"] is None:
            raise Exception("Invalid param ID parameters.")

        job = job_manager.get_job(params["id"])
        return jsonify(job)

B) 在应用程序的核心。这是业务层,其中应用逻辑来转换数据。

class JobManager:
   def get_job(self, job_id) -> None:
        if job_id is None:
            raise Exception("Invalid param ID parameters.")

在更复杂的场景中,可以使用validator 服务或装饰器,但问题是相同的:在代码的哪一点是验证用户输入的最佳实践。

如果答案不是以上任何一种情况(或两者都不是),请提供有关您的答案的更多详细信息。如果可能,请尝试与语言无关,因为我正在寻找可以在任何地方应用的最佳实践。

【问题讨论】:

【参考方案1】:

Parsing 通常应发生在信息进入您的系统的位置,或尽可能接近该位置。

因此肯定是“应用层”而不是“域层/业务层”:要么由控制器本身调用,要么非常接近它。 (通常不是“在”控制器中,因为您应该能够测试解析器而无需耦合到一堆 HTTP 仪式。)

@api.route('/job', methods=['GET'])
def get_jobs():
    try:
        job_id = parse_job_id(params["id"])
        job = job_manager.get_job(job_id)
        return jsonify(job)

在类型化语言中,这可以让您的生活轻松很多,因为您大大减少了必须询问“这种通用数据结构是否包含我期望的信息?”的地方的数量

另一方面,对业务政策的检查通常属于领域层。

例如:如果您的 API 需要日期,则检查日期是否实际存在,以及日期是否以适当的 ISO-8601 格式表示,等等……这些检查都是作为一部分进行的控制器对输入的解析。

另一方面,检查日期是否“在未来”,或者日期是否在保修期内,或者......这些检查属于您的域代码。

【讨论】:

有趣的是,Java 包含一个@Future 注释,用于在解析层进行验证。【参考方案2】:

通常,我将验证分为几个阶段:

    在 REST 控制器中立即对输入数据进行语法验证 服务中的业务逻辑验证

第一次验证应该只标记绝对错误的东西;例如缺少必填字段、类型不匹配、无法解析的字符串、任何代码注入尝试以及安全令牌的存在(或缺乏)。

当此验证通过时,输入数据至少在语法上是正确的,并且可能会被传递到服务,在那里进行更严格的验证;即输入数据在商业方面是否有意义,具有该 ID 的资源是否存在 - 等等。

短版:第一个验证查找明显错误的内容,而随后的验证确保输入数据正确且对业务有意义。

【讨论】:

以上是关于在哪里验证发送到 API 的参数?的主要内容,如果未能解决你的问题,请参考以下文章

我在哪里可以找到有关 SP 如何使用其私钥签署身份验证请求并将其发送到 IdP 的 URL 的信息?

如何使用POSTMAN发送请求参数到一个写好加解密方法的接口里

React 和 Express 身份验证

如何显示从 Node.js API 发送到 Next.js 的验证错误

使用 Postman 测试 API,Postman 调用在哪里?

尝试通过函数参数将正文发送到 API 时出现 KeyError