Cookie 策略

Payload 提供了通过 HTTP-only cookies 进行身份验证的能力。这些 cookie 可以从 loginlogoutrefreshme 等认证操作的响应中读取。

提示: 你可以通过 req.user 参数在 访问控制钩子 中访问已登录用户。了解更多详情

浏览器自动包含

现代浏览器在直接向 URL 发起请求时会自动包含 http-only cookies。这意味着如果你的 API 运行在 https://example.com 上,当你登录后访问 https://example.com/test-page 时,浏览器会自动为你包含 Payload 的认证 cookie。

HTTP 认证

然而,如果你使用 fetch 或类似 API 从 REST 或 GraphQL API 获取 Payload 资源,则必须指定包含凭证(cookies)。

包含凭证的 Fetch 示例:

const response = await fetch('http://localhost:3000/api/pages', {
  credentials: 'include',
})

const pages = await response.json()

关于如何在从你的应用向 Payload API 发送请求时包含 cookie 的更多信息,请阅读 MDN 文档

提示: 要确认登录后浏览器中是否正确设置了 Payload cookie,可以使用浏览器的开发者工具 > 应用 > Cookie > [你的域名]。开发者工具仍会显示 HTTP-only cookies。

CSRF 攻击

CSRF(跨站请求伪造)攻击既常见又危险。通过使用 HTTP-only cookie,Payload 消除了许多 XSS 漏洞,但 CSRF 攻击仍有可能发生。

例如,假设你有一个流行的应用 https://payload-finances.com,允许用户管理财务、发送和接收资金。由于 Payload 使用 HTTP-only cookie,这意味着浏览器在向你的域名发送请求时会自动包含 cookie——无论请求是由哪个页面发起的

因此,如果 https://payload-finances.com 的用户已登录并在互联网上浏览,他们可能会偶然访问到带有恶意意图的页面。请看以下示例:

// malicious-intent.com
// 以你的身份发起认证请求

const maliciousRequest = await fetch(`https://payload-finances.com/api/me`, {
  credentials: 'include',
}).then((res) => await res.json())

在这种情况下,如果你的 cookie 仍然有效,malicious-intent.com 就能够像上面那样以你的身份发起请求。这就是 CSRF 攻击。

CSRF 防护

定义你信任并愿意接受来自这些域的 Payload HTTP-only cookie 请求的域名。使用 Payload 基础配置中的 csrf 选项来实现这一点:

// payload.config.ts

import { buildConfig } from 'payload'

const config = buildConfig({
  serverURL: 'https://my-payload-instance.com',
  // highlight-start
  csrf: [
    // 允许进行 cookie 认证的白名单域名
    'https://your-frontend-app.com',
    'https://your-other-frontend-app.com',
    // 如果定义了 `config.serverURL`,默认会自动添加
  ],
  // highlight-end
  collections: [
    // 集合配置
  ],
})

export default config

跨域认证

如果你的前端与 Payload API 位于不同域名下,默认情况下将无法使用 HTTP-only cookies 进行认证,因为浏览器会将其视为第三方 cookies。以下是几种解决策略:

1. 使用子域名

cookies 可以在子域名间共享而不会被视作第三方 cookies。例如,如果你的 API 位于 api.example.com,那么你可以从 example.com 进行认证。

2. 配置 cookies

如果第一种方案不可行,你可以通过配置认证集合的 cookies 来绕过这个限制,实现以下设置:

SameSite: None // 允许 cookie 跨域
Secure: true // 确保仅通过 HTTPS 发送
HttpOnly: true // 确保无法通过客户端 JavaScript 访问

配置示例:

{
  slug: 'users',
  auth: {
    cookies: {
      sameSite: 'None',
      secure: true,
    }
  },
  fields: [
    // 你的认证字段放在这里
  ]
},

如果你在 Payload 配置中设置了 cors,将不能再使用通配符,需要明确指定允许的域名列表。

须知: 设置 secure: truehttp://localhost 或任何非 HTTPS 域名下开发时将不起作用。对于本地开发环境,你应该根据环境条件将其设置为 false