从 JavaScript 应用程序访问 API 时出现 CORS 错误

这对我来说本来是个不错的答案,但我无法让基于 Header 的认证生效,因此正尝试改用表单方式,同时也遇到了 CSRF 问题。有什么解决方案吗?我正尝试通过 API 创建新主题。

我们需要更多信息才能提供帮助。您能分享一段代码片段,展示您是如何尝试使用基于请求头的身份验证的吗?

我遇到的问题主要在于:每当我尝试使用基于头的认证进行调用时,系统接受的请求头始终是 “User-Api-Key” 和 “User-Client-Id”,而不是 “Api-Key” 和 “Api-Username”,因此导致了 CORS 错误。我认为我不需要基于用户的密钥。我只是想执行一个简单的认证请求来创建新话题。如果我尝试使用 “User-Api-Key”,则会收到 403 错误。

以下是示例代码(Angular TypeScript),但其他设置应类似:

    createNewTopic(postBody: any) {
        let url = "myserver.com/posts.json";
        let CATEGORY_ARTICLES = 6;
        let topicContent = `
          <p>Some content
        </p>
        <p>Did that work?</p>
        `;
        let post = {
          "title": "Tdk Test 1",
          "raw": topicContent,
          "category": CATEGORY_ARTICLES,
          "target_usernames": "tdekoekkoek",
          "archetype": "",
          "created_at": new Date()
        }
        let headers = new HttpHeaders()
          .set("Accept", "application/json")
          .set("User-Api-Key", DISCOURSE_API_KEY)
          .set("User-Key", "system")
          .set("Content-Type", "application/x-www-form-urlencoded")
        let options = {headers: headers};
        return this.http.post(url, post, options);
      }

user-api-keyuser-client-id 是完全不同的认证方式。普通的 API 密钥无法配合这些请求头使用。当你使用正确的请求头名称(api-keyapi-username)时会发生什么?

我遇到了 CORS 错误,因为服务器期望接收 User-Api-Key 头。我检查了 OPTIONS 响应中预期的请求头,确认正是如此。本论坛其他位置有一个类似的主题,有用户在从 JavaScript 应用调用时也遇到了这个问题。

哦,所以您正试图从客户端 JavaScript 应用程序发起此请求?出于多种原因,这是不允许的。例如,如果您在 JavaScript 应用的源代码中包含了管理员 API 密钥,任何用户都可能获得对您论坛的完整管理员访问权限。这里 有一个关于该主题的先前讨论。

是的,这正是我试图做的。这一点应该有更清晰的文档说明。自开始使用 Discourse 以来,这一直是我整体的策略。感谢您的帮助。我已经为此奋战了数天,并阅读了相关文档。由于我目前正在构建一个无服务器应用(尽管我确实可以访问一个 Node.js 服务器),我将不得不重新思考我的整个方法。

这并不是 Discourse 特有的限制——一般来说,将管理员凭证包含在网站的源代码中是一个糟糕的做法。

如果您能从您的 Node.js 服务器发起 Discourse API 调用,那可能是最佳解决方案。如果您的应用程序必须是纯客户端的,那么请求用户特定的 API 密钥是一个选项,尽管其设置要复杂得多:User API keys specification

说实话,在启用 CORS 的情况下从客户端应用访问 API 是非常普遍且标准的做法。我无法相信竟然没有更安全的实现方式。整个行业都围绕着一类托管 API 展开,这些 API 需要从不同域名进行访问。至于使用用户 API 进行访问,我虽见过如何创建此类 API,但对实际所需的凭据仍不清楚。在使用该方法时,我总是收到 403 权限被拒绝的错误。

我想我遇到了类似的情况。

关于使用场景的一些背景:

我使用 Discourse 作为后端,并使用 VueJS 构建前端。我打算仅使用 REST API。对于平台上的每个用户,我都创建了一个用户 API 密钥,并在身份验证时同时使用两个头部(Api-Key 和 Api-Username)。

每个用户都安全地与我们服务器进行身份验证,然后接收其 Discourse Token 用于后续认证。随后,我们希望在前端(VueJS)中使用此 Token 发送 API 请求(如发布话题、帖子、编辑等)。

没有任何硬编码内容,所有 Token 均在通过正确身份验证后获取。

问题:
尽管我已在 app.yml 中启用了 CORS,并在管理员设置的“安全”部分进行了配置,但我仍然收到 CORS 错误消息。

错误信息:Request header field api-key is not allowed by Access-Control-Allow-Headers

我遇到 CORS 错误是否出于相同原因?为什么在使用 “Api-Key” 和 “Api-Username” 头部时 CORS 请求会被阻止?我可能误解了它们的使用场景。

编辑:
我对自己的误解有一个推测。当我通过 REST API 的“为用户生成 api_key”端点创建用户 API 密钥时,该密钥是否具有管理员权限?它是否不仅仅是一个用于发帖和评论的用户密钥?如果是这样,那么我就理解这种限制了。

如有需要,请纠正我。

@david discourse 不能简单地让服务器用 HMAC 签名一个 session secret,而这个 session secret 又可以用来签名给定 session 中的内容吗?如果它被盗了,那么 session cookie 或 CSRF nonce 应该也不会被盗。这有点像证书链——你不必把根密钥放在浏览器里。

这些仅用于管理员 api。我的理解是,对于 JavaScript 客户端,您需要如上所述,查看 User API keys specification