如何将 cookie 用于 HTML 和 API 调用具有不同域的站点?

Posted

技术标签:

【中文标题】如何将 cookie 用于 HTML 和 API 调用具有不同域的站点?【英文标题】:How can I use cookies with a site where the HTML and the API calls have different domains? 【发布时间】:2020-07-17 02:15:29 【问题描述】:

我在静态服务器(恰好是 Amazon S3)上托管一个单页应用程序网站,因此它是从我的应用程序的 URL 提供的,比如说“example.com”。所以该网站位于“https://example.com”。该站点使用使用 javascript 的 fetch() 调用进行的 API 调用来执行站点的功能。因为 example.com 指向一个静态服务器,API 调用转到不同的域,我们称之为“xyz.execute-api.cloudhost.com”(它恰好位于亚马逊的 API 网关后面)。

我想使用 cookie 来管理用户会话。也就是说,我希望一个 API 调用在响应中返回一个 Set-Cookie 标头,该标头将在浏览器上存储一个 cookie,并且我希望某些其他 API 调用在请求上传递一个 Cookie 标头,然后可以在 API 中对其进行验证。 cookie 将始终来自 API 并返回到 API(不是页面站点,因为页面本身托管在静态服务器上)。我希望在会话之间保存 cookie(具有一些到期生命周期,并且了解浏览器可能会由于空间限制或用户操作而清除它)。

但这很难做到。首先,我的 API 调用都是到一个单独的域,所以我必须使用 CORS 来授权调用。当我使用 CORS 时,服务器必须在 Access-Control-Allow-Headers 列表中包含“Cookie”,否则将不会返回。此外,当我使用 Javascript 的 fetch() API 进行调用时,我需要指定包含这样的凭据:

fetch(url, method: "POST", credentials: "include")

...否则 cookie 将不会被发送。返回 cookie 的 API 调用不需要接收 cookie,但我也必须为此指定 credentials: "include",否则浏览器将忽略该 Set-Cookie 响应标头。

我还需要正确配置 cookie 本身。各种 API 调用有不同的路径,所以我需要在我的 Set-Cookie 标头中指定Path=/。我更喜欢设置SameSite=StrictSecureHttpOnlyMax-Age 的值,但如果需要我愿意灵活处理。

这就是我所知道的。我仍然无法让我的 cookie 被放置(使用 Set-Cookie)并以跨平台的方式返回到服务器(在 Cookie 中)。因为页面域与 API 域不同,我可能需要指定 SameSite=None,但如果这样做,recent standards changes 可能还需要我设置 Secure(这很好)。即便如此,我也无法让所有主流浏览器都返回 cookie。我还希望用相同的密钥设置一个新的 cookie 会替换现有的,但我也无法让它工作——当它返回时,我看到了两个 cookie。

在这种情况下使用 cookie 的正确方法是什么?

【问题讨论】:

【参考方案1】:

正如您特别提到的,您希望从单独的站点向 API 站点发起这些请求,这意味着它们本质上是跨站点或第三方请求,因此 cookie必须 标记为SameSite=None; Secure

如果您想使用 SameSite=StrictSameSite=Lax 之类的内容,则需要改为在 SPA 中管理 cookie。这可能更可取,因为它允许您将会话标识符或令牌存储在那里,然后将其作为单独的字段或标头传递给您的 API。这样您的 API 不依赖于 cookie,这可能是可取的。

【讨论】:

以上是关于如何将 cookie 用于 HTML 和 API 调用具有不同域的站点?的主要内容,如果未能解决你的问题,请参考以下文章

将身份验证同时用于 MVC 页面和 Web API 页面?

将单独的 Dyno 用于反应前端和 Django 后端时的 Cookie

如何使用.Net Core cookie中间件ticketdataformat将Jwt令牌从Api保存到c#中的cookie

JavaWeb会话管理:Cookie

正确设置 IdentityServer4 Cookie 用于登录,JWT 令牌用于 API 授权

用于保护 REST api 的 Apache Shiro