用户 API 密钥规范

如果遵循非常特定的协议,Discourse 包含一个为每个用户生成 API 密钥的系统。此功能促进了“应用程序”对 Discourse 实例的访问,而无需管理员介入。

高层描述

从高层来看:

  1. 客户端(桌面应用程序、浏览器插件、移动应用程序)生成私钥/公钥对和返回 URL

  2. 客户端重定向到 Discourse 上的路由,向 Discourse 提供其公钥

  3. Discourse 获得用户使用应用程序的批准

  4. Discourse 生成用户 API 密钥

  5. Discourse 重定向回返回 URL,并使用包含用户 API 密钥的公钥加密有效负载

详细信息

用例:

  1. 代表最终用户轮询 Discourse 站点以获取多个站点的通知计数的桌面应用程序。

  2. 代表最终用户轮询 Discourse 站点并处理推送通知的移动应用程序。

  3. 为最终用户提供有关各种 Discourse 站点的仪表板的 Web 应用程序。

  4. 将 Discourse 作为通用公司应用程序一部分进行消费的第三方应用程序的自定义集成。例如:将 Discourse 社区通知集成到 hopscotch 应用程序中。

设计:

站点设置

  • allow_user_api_key_scopes:用户 API 密钥的允许访问范围。范围在此处定义。可用的内置范围包括:readwritemessage_buspushone_time_passwordnotificationssession_infobookmarks_calendaruser_status(插件可以注册其他范围)。

  • user_api_key_allowed_groups:控制允许生成用户 API 密钥的组(默认为管理员、版主和 trust_level_0)

  • allowed_user_api_push_urls:可作为推送通知目标的站点列表

  • allowed_user_api_auth_redirects:生成用户 API 密钥后允许的重定向目标

全局设置

  • max_user_api_reqs_per_minute:50
  • max_user_api_reqs_per_day:4000

UX 元素

如果已授予任何用户 API 密钥,Discourse 会在用户页面中显示应用程序选项卡。

应用程序选项卡将列出:

  • 应用程序名称,例如:(“Discourse Notifier”)
  • 上次使用日期
  • 批准日期
  • 已授予的访问范围列表
  • 撤销访问按钮,以便您可以轻松撤销任何密钥

API 密钥授权 UI

每个密钥都必须由最终用户在明确解释正在发生的事情的页面上显式授权,例如:

“Discourse Notifier”正在请求以下对您的账户的访问权限:

  • 读取和清除通知
  • 读取用户会话信息
  • 创建一次性登录令牌

[授权]

API 密钥生成流程

API 仅在用户端需要单个 GET 请求。

https://sitename.com/user-api-key/new

:exclamation: 从 Discourse 2.1 开始,如果长时间未使用,这些用户 API 密钥将自动过期。站点设置:revoke user api keys unused days 默认设置为 180

参数:

  • auth_redirect:带有生成的令牌的返回重定向 URL
  • application_name:发出请求的应用程序名称(将显示在用户账户的应用程序选项卡中)
  • client_id:客户端的唯一标识符
  • nonce:由客户端生成的唯一 nonce。这将回显在加密有效负载中,以便客户端可以验证响应真实性
  • scopes:允许密钥的访问范围的逗号分隔列表,请参阅 allow user api key scopes 以获取可用范围的完整列表
  • push_url:推送通知的 URL(仅在范围中包含 pushnotifications 时必需且有效)
  • public_key:客户端生成的密钥对的公钥部分
  • padding(可选):用于加密有效负载的 RSA 填充模式。接受的值是 pkcs1(默认)或 oaep。建议新应用程序使用 OAEP

在调用 /user-api-key/new 并带有正确参数后,可能会发生两件事

  1. 如果用户未登录,我们将重定向到登录(登录后我们将恢复授权)
  2. 一旦用户登录,他们将看到授权 UI

授权允许后,系统将重定向回 auth_redirect 中定义的 URL,并包含一个加密的 payload 参数,其中包含一个 JSON 对象,包含生成的用户 API 密钥 (key)、nonce、推送状态 (push) 和 API 版本 (api)。如果请求了 one_time_password 范围,还将包含一个单独的加密 oneTimePassword 查询参数。出于额外安全考虑,client_id 不会回显。

检查 API 版本

Discourse 中的用户 API 是版本化的。客户端可以通过向 https://sitename.com/user-api-key/new 发出 HEAD 请求来检查 Discourse 站点的 API 版本。响应将包含一个名为 Auth-Api-Version 的标头,其中包含站点 API 的版本号。

使用 API

使用客户端 API 将 somewhat 不同于当前的管理员 API。

客户端可以指定 2 个标头:

User-Api-Key(必需):生成的密钥

User-Api-Client-Id(可选):提供此以更新数据库中为此 api_key 存储的 ‘client id’。

一旦指定了这些标头,客户端就可以像往常一样对 API 执行请求。

生成一次性登录密码

从版本 4 开始,API 包含一个特殊范围:one_time_password 范围,它允许客户端使用用户 API 密钥生成一次性密码。如果客户端在按照上述步骤生成 API 密钥时包含此范围,则加密的 oneTimePassword 将作为单独的查询参数包含在重定向回客户端中。

或者,客户端可以向 /user-api-key/otp 发出 GET 请求,并带有以下参数:

  • auth_redirect
  • application_name
  • public_key
  • padding(可选)

并带有 User-Api-Key 标头。

此请求将重定向到 Discourse 中的屏幕,该屏幕将要求用户允许应用程序访问站点。如果用户批准,站点将重定向回 auth_redirect 中定义的 URL,并包含一个加密的 oneTimePassword 参数,其中包含客户端可用于通过请求 https://sitename.com/session/otp/ONE-TIME-PASSWORD 登录站点的一次性密码。(一次性密码仅有效 10 分钟。)

撤销 API 密钥

要撤销 API 密钥,请向 /user-api-key/revoke 发出带有 User-Api-Key 标头且无参数的 POST 请求。


最后由 @SaraDev2022-07-13T00:00:00Z 审核

31 个赞
Generating User Api Keys with REST API
Discourse Login & Registeration
Discourse sso login using Rest API
Custom Push Notifications: allowed user api push urls
Beta testing the iOS mobile app
How can I get user details via the user api key?
Authorization from a desktop application (and base domain site)
Secure way of encrypting payload in Javascript for user authentification
Can non-admin user issue their own API key?
Automatic Login from iOS/Android app
Delegated authentication for Discourse Mobile app
Generating User Api Keys with REST API
Generating User Api Keys with REST API
API CORS Headers Incorrect
Get back Username with API Key?
Is there any documentation on the User/Mobile API?
Passing draft text into a new response
Discourse Hub "connect"
Generate User API Keys for testing
Consolidated API Requests in the thousands yet our site has no active API keys listed, is this a concern?
Having issue accessing the Discourse APIs from react app
Discourse REST API Documentation
Having issue accessing the Discourse APIs from react app
CORS error accessing API from javascript application
Does Discourse have support for PAT tokens?
API key creation
Access via Discourse API, key and/or user rejected
Feasibility of allowing a User Api Key client to register a valid auth_redirect
Implement discourse Apple login using API
Thousands of user api requests and invalidation
Are User API Keys Not Generated When Logging in via Login Link?
Confusion about API Authenticated User
Confusion about API Authenticated User
Generate User Api Key Without User Approval
How to use discourse api in react native?
"Api-Key" and "Api-Username" for try.discourse.org?
How can I allow users to like posts using RESTapi
Allow_user_api_key这个设置在哪开启
Dexo - A Native iOS Client for Discourse
Acess-Control-Allow-Headers CORS Error with API after updating discourse
CORS error accessing API from javascript application
Clip To Discourse Chrome Extension - now with User API capability!
Unable to create "Single User" level API key, always defaults to "All Users"
Discourse index
Clip To Discourse Chrome Extension - now with User API capability!
Authentication Protocol re: App Integration
Embed Discourse in a native app?
Request header field User-Api-Key is not allowed by Access-Control-Allow-Headers
Request header field User-Api-Key is not allowed by Access-Control-Allow-Headers
Request header field Content-Type is not allowed by Access-Control-Allow-Headers
Create apikey for user programmatically as admin
How to fix 'Cannot read property '_links' of undefined'
Allow API use by regular users, not just admins
The purpose of the 2 Discourse API systems
Bot writer's tip: Processing every post
Using Zapier without being admin
Per User API Keys Not Working
Acess-Control-Allow-Headers CORS Error with API after updating discourse
Work with discourse users on an SPA

There are places I’ve strongly considered writing a delayed post tool, so I can compose a bunch of “word of the day” type things to keep going while I’m on vacation. Doing it without proper API access and pretending to be a browser seems somewhat more complicated than on other forum software.

(Just as an example of another use case.)

That is a good example, but keep in mind, our default will be only to enable read tokens, not write ones. Site admins will have to opt to allow write tokens.

Completely agree that the _t cookie hacks are a huge problem.

2 个赞

Does max_user_api_calls_per_key_day setting apply to admin-created keys at /admin/api?

1 个赞

Nope only to user api keys, we can look at adding extra limits for standard Api keys, it is a good safeguard

1 个赞

To be clear, this is not implemented yet, correct?

No, it’s there (for almost 2,5 years now) - Admin - Settings - User API.

4 个赞

As of Discourse 2.1 these user api keys now auto-expire if left unused for long periods of time, correct @sam?

2 个赞

Correct the site setting: expire user api keys days is set to 180 out of the box.

2 个赞

Okay, but you have to have admin access to see that page yes? And as an admin, it seems I can only create 1 key, so can’t create many keys for different users. confused.

1 个赞

What are you trying to accomplish? It’s not clear because there is this (user api keys) and regular API tokens (which is what I think you are after) that admins can create for multiple users, but you have to do that from the individual user’s page inside of the admin dashboard by clicking on the “generate” button on the “API Key” field.

4 个赞

Thanks! Yes, “regular API tokens” for users is what i was after. I’m sure I’d seen that a million times, and never realized it was there. :heavy_check_mark:

3 个赞

Hey everyone I’m not sure if this was resolved? I see that it’s possible to create an “All Users” and (per user) level API token as an admin, but I’m interested in giving a user the power to generate his/her own token. Has there been work done on this? It sounds like the original thread was getting at this idea, and then it was lost. Thanks!

Download the mobile App and then add a site, that uses the user api key system you have to follow a very strict workflow, no plans to expose arbitrary generation of keys in user prefs

3 个赞

Thank you! I downloaded the app, and then realized that the sites I belong to don’t have this enabled (I’ve been testing on my local machine with the Dockerized discourse). Just to make sure we are talking about the same thing - I’m interested in generating tokens to use just a scoped subset of functions (and not global API keys to do all the things). Is this what you are talking about?

It seems like, given that there is an endpoint to generate tokens, it would be logical to provide this function (to users with a certain trust level, for example) from within the site. Otherwise, it would need to be the case that the site generates some external page (with a server to hide an admin token) to generate the keys for the user. Is it the case that 1. there is no internal generation of tokens for the user (and why not?) and 2. Nobody has created some external app (javascript, flask, anything really) to perform this action?

1 个赞

Yes.

Possibly, conceptually

  1. This is tricky to consume cause you need to use custom HTTP headers (by design)

  2. It would be very hard to educate even TL3 users about what the point is of this thing.

I prefer not to ship UI for this in core, but maybe you should write a plugin for your specific use case?

Can you explain a bit more about the “why” here?

The design of the system centers around “I have an external dedicated program”, “this program knows how to follow Discourse protocol”, “It asks for token”

API keys (non user ones) are much easier to consume cause you just append them after the ?

4 个赞

Can I pass the API key generated from the user page on this? I was trying to use that API key and seeing ‘You are not permitted to view the requested resource.’ error on /categories.json API request

大家好

如果这是重复提问,敬请见谅。尽管相关步骤编写得非常清晰,但我仍难以完全理解。

我在 https://forum.domain.com 上部署了 Discourse,并在 https://development.domain.com 上有一个网站,需要调用 Discourse 接口来拉取和设置部分数据。

所有请求通过 Postman 使用 Api-Username 和 Api-Key 都能正常发送,没有问题。

但在通过 JavaScript 进行跨域请求时,Discourse 不允许使用 Api-Username,因此我不得不按照该线程中描述的流程操作,即使用 User-Api-Key 和 User-Api-Client-Id。

我主要需要了解以下参数在下方示例请求中的含义以及获取方式:PUBLIC_KEY、NONCE、CLIENTID。

https://forum.domain.com/user-api-key/new?public_key=PUBLIC_KEY&nonce=NONCE&scopes=SCOPES&client_id=CLIENTID&application_name=DEVELOP&auth_redirect=XXX

最后,这种流程是否允许从 https://development.domain.comhttps://forum.domain.com 发起无缝的 API 请求,而无需额外进行身份验证?

附注:论坛与发起请求的网站之间已设置 SSO,因此用户将处于登录状态。

感谢任何指导。

稍等,这是按用户设置的功能吗?你们是否允许任意用户执行此操作?

我们的服务器 API 目前支持基于请求头的身份验证,因此可以像用户 API 密钥一样与 CORS 协同工作。如果您希望限制权限范围,并允许最终用户自行生成密钥(而非由管理员生成),则应使用用户 API 密钥。

2 个赞

我认为不需要为每个用户单独分配一个密钥……一个管理员密钥就足以满足我的需求。

通过 Postman 调用 API 完全没有问题。例如,使用 api-key 作为请求头发起对 /notifications.json?username=alanmurphy 的 GET 请求,可以正常返回数据。

如果我在 Discourse 安装的控制台中触发该请求,同样可以正常获取数据,如下所示:

var xhr = new XMLHttpRequest();
xhr.addEventListener(“readystatechange”, function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open(“GET”, “https://**********.com/notifications.json?username=alanmurphy”);
xhr.setRequestHeader(“api-key”, “d06ca53322d1fbaf383a6394d6c229e56871342d2cad953a0fe26c19df7645ba”);
xhr.setRequestHeader(“api-userame”, “system”);
xhr.send();

一切正常:+1:

但是,如果我从希望联系 Discourse 的子域名发起该请求,系统会提示被 CORS 策略阻止:请求头字段 api-key 未被 Access-Control-Allow-Headers 允许。

允许的请求头包括:

Content-Type, Cache-Control, X-Requested-With, X-CSRF-Token, Discourse-Visible, User-Api-Key, User-Api-Client-Id

如果能得到关于跨域请求应传递哪些认证参数以及这些参数获取位置的指导,将非常有帮助。

附:我的 Discourse 已配置为允许来自该域名的跨域请求,因此我认为问题纯粹出在请求头上。

谢谢

1 个赞