Skip to main content

本页目的

在限时分享链接中,如果希望直接使用签发时确定的条件,除了验证 URL 签名之外,还需要统一从哪里获取值。 本页以一个示例进行说明:在 URL 中包含报表类型和输出格式,并返回用于预览的 JSON。 本页适用于 Laravel 13。URL 生成的整体介绍请参阅 URL 生成,获取输入的基础知识请参阅 HTTP 请求。
签名并不保护整个请求。表单和 JSON 请求体不在签名范围内。 已签名的查询值应在签名验证之后,通过 $request->query('format') 这样的方式获取。 使用 input()、all() 或动态属性时,可能会获取到未签名的请求体中的值。GET 请求同样需要做此区分。

签名保护的范围

input() 不仅处理查询字符串,也处理请求体。Laravel 在合并这些输入时,请求体中的值优先于查询字符串中的值。 而 query() 只获取查询字符串中的值。 签名验证成功,与之后读取的值是否已签名,是两件需要分别确认的事情。

实现限时预览链接

1. 定义进行验证的路由

在 routes/web.php 中定义一个必须带签名的命名路由。 这里不操作数据库或文件,只返回接收到的条件。
  • signed 中间件会在闭包执行前验证签名和有效期。若无效,则返回 403。
  • 使用 query() 从查询字符串中显式获取处理所需的值。
  • 校验针对获取到的数组进行。签名验证并不保证值的类型或业务上允许的范围。
本示例中传给 Validator::make() 的只有通过 query() 取出的值。 如果在用于校验已签名查询值的地方改用 $request->all(),就会处理到包含请求体在内的输入。

2. 在可信的签发流程中生成 URL

注册命名路由后,在签发链接的处理中使用以下代码。 report 和 format 不是路径占位符,因此会被添加到查询字符串中。
该 URL 除了指定的条件外,还包含 expires 和 signature。 expires 和 signature 是 Laravel 使用的保留参数,请不要将它们用作业务参数名。 在实际应用中公开签发流程时,不要让任何人都能以任意条件签发链接,并进行必要的认证和授权。

3. 确认正常使用

在有效期内直接打开签发的 URL,会返回以下 JSON。
链接过期后,路由上的 signed 中间件会返回 403。 签名 URL 并不是一次性令牌。在本示例中,有效期内可以重复使用同一个 URL。 如果只允许使用一次,需要在签名之外另行管理已使用状态。

区分从验证中排除的值

如果希望允许前端追加的页码等参数,可以通过 hasValidSignatureWhileIgnoring(['page']) 将其从签名验证中排除。 但被排除的值任何人都可以修改,因此不要将其视为已签名的条件。 例如,用于显示的 page 与签发时固定的 report、format 作用不同。 不要仅仅为了方便,就排除那些用于判断目标数据、接收者、费用等的值。
上面的实现示例使用的是普通的 signed 中间件,因此 page 也没有被排除。 如果需要追加查询参数,请先确定生成端和验证端分别将哪些内容纳入签名。

使用相对签名时

在签名中不包含域名的设计中,需要组合使用生成时的 absolute: false 和验证时的 signed:relative。
此时,将前面路由中的 middleware('signed') 改为 middleware('signed:relative')。 即使使用相对签名,请求体也不会被签名,因此通过 query() 获取值的方针不变。

实现检查清单

  • 接收路由强制要求签名验证。
  • 通过 query() 获取已签名的查询值。
  • 另行校验值的格式和允许范围。
  • 没有将从签名验证中排除的值当作签发时固定的条件使用。
  • 生成端与验证端的绝对签名、相对签名设置保持一致。
  • 没有将知道 URL 等同于已登录用户的权限。

相关页面与一手资料

最后修改于 2026年10月16日