Discourse OAuth2 基础

:discourse2: 摘要 Discourse OAuth2 Basic 支持基础的 OAuth2 提供商,前提是这些提供商拥有可通过令牌获取用户详情的 JSON API 端点。
:open_book: 安装指南 此插件已随 Discourse 核心捆绑。无需单独安装该插件。

功能

此插件允许您使用基础的 OAuth2 提供商作为 Discourse 的身份验证方式。它应能与许多提供商配合使用,但前提是它们必须提供用于检索登录用户信息的 JSON 端点。

这对于使用不太流行的登录提供商的用户特别有用。如果您想使用 Google、Facebook 或 Twitter,这些已内置于系统中,无需此插件。您也可以在我们的 GitHub 仓库 中查找其他登录提供商。

配置

基础配置

  1. 首先,向您的 OAuth2 提供商注册您的 Discourse 应用程序。它将需要一个重定向 URI,格式如下:

    http://DISCOURSE_HOST/auth/oauth2_basic/callback

:information_source:DISCOURSE_HOST 替换为相应的值,并确保如果启用了 https 则使用 https。OAuth2 提供商应为您提供 client IDsecret,以及几个 URL。

  1. 访问您的 管理后台设置OAuth2 登录,并填写 OAuth2 提供商的基础配置:
  • oauth2_enabled - 勾选此项以启用该功能
  • oauth2_client_id - 来自提供商的客户端 ID
  • oauth2_client_secret - 来自提供商的客户端密钥
  • oauth2_authorize_url - 提供商的授权 URL
  • oauth2_token_url - 提供商的令牌 URL。

:information_source: 如果您无法确定上述设置的值,请查阅提供商的开发文档或联系其客户支持。

配置 JSON 用户端点

现在 Discourse 可以接收来自 OAuth2 提供商的授权令牌。不幸的是,Discourse 还需要更多信息才能完成身份验证。

我们需要一个 API 端点,以便根据令牌检索用户信息。

例如,OAuth2 提供商 SoundCloud 提供了这样的 URL。如果您拥有 SoundCloud 的 OAuth2 令牌,可以向 https://api.soundcloud.com/me?oauth_token=A_VALID_TOKEN 发送 GET 请求,并将返回包含用户信息的 JSON 对象。

要在 Discourse 上配置此功能,我们需要设置 oauth2_user_json_url 设置的值。在这种情况下,我们将输入以下值:

https://api.soundcloud.com/me?oauth_token=:token

其中 :token 部分告诉 Discourse 需要在身份验证完成后用其收到的授权令牌替换该值。

最后一步是告诉 Discourse JSON 中可用的属性有哪些。以下是 SoundCloud 的示例响应:

{
  "id": 3207,
  "permalink": "jwagener",
  "username": "Johannes Wagener",
  "uri": "https://api.soundcloud.com/users/3207",
  "permalink_url": "http://soundcloud.com/jwagener",
  "avatar_url": "http://i1.sndcdn.com/avatars-000001552142-pbw8yd-large.jpg?142a848",
  "country": "Germany",
  "full_name": "Johannes Wagener",
  "city": "Berlin"
}

oauth2_json_user_id_pathoauth2_json_username_pathoauth2_json_name_pathoauth2_json_email_path 变量应设置为指向 JSON 中相应的属性。

唯一必需的属性是 id —— 我们需要它以便在用户未来登录时能够找到正确的账户。其他属性如果可用也非常有用 —— 它们可以加快用户的注册流程,因为这些信息将自动填充到表单中。

以下是我配置 JSON 路径设置的方式:

  oauth2_json_user_id_path: 'id'
  oauth2_json_username_path: 'permalink'
  oauth2_json_name_path: 'full_name'

我使用了 permalink,因为它似乎比 JSON 中的 username 更符合 Discourse 对用户名格式的预期。请注意,我省略了邮箱路径:SoundCloud 不提供邮箱,因此用户首次注册 Discourse 时必须自行提供并验证邮箱。

如果您希望从 JSON 对象中获取的属性是嵌套的,可以使用点号。例如,如果 API 返回了如下不同的结构:

{
  "user": {
    "id": 1234,
    "email": {
      "address": "test@example.com"
    }
  }
}

您可以使用 user.id 作为 oauth2_json_user_id_path,使用 user.email.address 作为 oauth2_json_email_path

如果键本身包含点号,则需要用双引号将其括起来,或者使用反斜杠转义点号。例如,给定以下 JSON:

{
  "example.com/uid": "myuid"
}

您可以将路径指定为 example\.com/uid"example.com/uid"

:warning: 如果您设置了 oauth2_json_email_path,OAuth2 提供商 必须 确认用户确实拥有该邮箱地址。 否则可能导致 Discourse 账户被接管!

:discourse2: 由我们托管?此插件可在我们的商业版和企业版计划中使用。OAuth 2.0 & OpenID Connect Support | Discourse - Civilized Discussion

:spiral_notepad: 需要自动化用户注册?请参阅 Auto-provisioning user accounts when SSO is enabled

28 个赞
Keycloak with Discourse
Discourse SSO with OAuth2
Login from another user database
Shopify Integration
How can we enable Auth0 SSO in Discourse
OAuth2 integration with Drupal
OAuth connection of discourse
Login flow (Flask -> Discourse -> Flask) with OAuth
How to use Oauth2 service provided by discourse?
How to login to discourse from external website
Is "partial" SSO possible?
Set up Salesforce auth using OAuth2 basic support plugin
How to force users link phone number when they using Discourse?
OAuth2 Custom Redirects Plugin
Custom Login / Registration from another API
Login on discourse using mastodon credentials
Open source will support customized provider SSO
Oauth2 with fusionauth cert issues
Migrate a Jive Clearspace forum to Discourse
Configure sign up and log in with Auth0 using the OAuth2 Basic Plugin
Error during SSO integration - Wholistic Minds
What is supposed to go in “DISCOURSE_HOST”?
Custom Provider log-in with OAuth only sign-up/log-in
Discord, Google and Microsoft login, is oAuth2 enough?
Populating email field on login page
CodeBerg support
Gate our community to just members of our Shopify site?
Intergrate Discourse with keycloak
Integration into custom auth system where emails are not unique?
Twitter login doesn't work on meta
Setup DiscourseConnect - Official Single-Sign-On for Discourse (sso)
Question about Docker Manager?
Discourse OpenID Connect (OIDC)
🧩 How to Build an Android App User Community with Discourse? [HeyApks Project]
Bundling more popular plugins with Discourse core
Drupal 8 and Discourse shared SSO
Discourse for self hosting
Discourse + Intercom (Current User Id)
Auto-provisioning user accounts when SSO is enabled
ADFS Authentication
Pulling user auth0 sub from OAuth2.0 plugin
Suggestion for improving Integrated Authentication development
Github and Twitter Login/Sign-Up Functionality?
Automatically creating a user when logging in with Webflow/Memberspace
Switching out authentication for a passwordless alternative
Removing Yahoo login from Core, and deprecating OpenID 2.0
Shopify Integration
SSO with TownNews CMS
SSO and Auth0

你好,

我们正尝试使用 OAuth2 Basic 将 Discourse 与我们的应用程序集成,但在日志中遇到以下错误:
注意:我们在调试连接时使用了 NGROK。

OAuth2 Debugging: request POST https://formshare.ngrok.io/oauth2/token

Headers: {"User-Agent"=>"Faraday v1.9.3", "Content-Type"=>"application/x-www-form-urlencoded", "Authorization"=>"Basic S2k2SFZtTVpuSTFHUExiRXVlWVJDN4CbOkNvb1k0anlQemt3dWNRV21Sa2FWOVNnbHZLbjJFT3cxc3BIMmtMck9yY21vNDM4Tg=="}

Body: {"client_id"=>"Ki6HVmMZnI1GPLbEueYRC4Cb", "client_secret"=>"...some_secret_...", "grant_type"=>"authorization_code", "code"=>"5pPCrsp0pZ84373MNaHh2cuskfc8AlbfmdwMBFIVW4n4z9aX", :redirect_uri=>"https://community.formshare.org/auth/oauth2_basic/callback"}

------------------

OAuth2 Debugging: response status 200

From POST https://formshare.ngrok.io/oauth2/token

Headers: {"content-length"=>"108", "content-type"=>"text/html; charset=UTF-8", "date"=>"Thu, 01 Sep 2022 21:42:08 GMT", "ngrok-trace-id"=>"79cdc3f1c3eae5e37a30796aebbf9bd6", "server"=>"gunicorn"}

Body: {"token_type": "Bearer", "access_token": "p0FVuwjSXL1ZINEklMAVqUlpZxSll1SgnbpE8YWP4C", "expires_in": 864000}

-----------------------------------

(oauth2_basic) Authentication failure! invalid_credentials: OAuth2::Error, {"token_type": "Bearer", "access_token": "p0FVuwjSXL1ZINEklMAVqUlpZxSll1SgnbpE8YWP4C", "expires_in": 864000}

我们留空了“oauth2 callback user id path”和“oauth2 callback user info paths”这两个参数。

有什么想法吗?

我可以使用此方法向 Microsoft 的 XBL 服务进行身份验证吗?

我猜逻辑会与此类似?

大家好。我尝试使用我们的内部 Oauth2 服务器和授权码流来配置此插件。

当用户点击“使用 Oauth 连接”时,/authorize 端点会正常工作,并且会向回调返回一个 code。但之后 Discourse 会显示一个通用的 500 错误“哎呀。驱动此讨论论坛的软件遇到了意外问题”,并且不会访问 /token 端点。

错误日志显示如下
OAuth2::ConnectionError (FinalDestination: 所有已解析的 IP 都被禁止) lib/final_destination/ssrf_detector.rb:74:in lookup_and_filter_ips' lib/final_destination/http.rb:13:in connect’ lib/midd

hostname discourse-app
process_id 653
application_version 702f27e6ee10ac257f5fee3f331d05f5fa5d7a45
HTTP_HOST *****
REQUEST_METHOD GET
HTTP_USER_AGENT Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36
HTTP_ACCEPT text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
HTTP_REFERER *****
HTTP_X_FORWARDED_FOR *****
HTTP_X_REAL_IP *****
time 晚上 10:25
params
code def50200babf84f7376f99fefa34369d876566b6bc0a341d8fba431999a72549ac06f6aad01df6fa43061707c525ba5d725ad
state 20139e0a134a5972566d4ddb6f7f9092a2cddb9e5216973a

据我所知,这是某个 IP 地址的问题?目前 Oauth2 服务器托管在我的开发环境中(localhost),并且授权和令牌端点已相应配置。有问题吗?

问题已找到:
1)出于某种原因,/token 端点从未被调用。在管理员参数中填写了与 oauth 相关的最多选项后,该端点被调用但没有响应。
2)我忘记了是 Discourse 服务器会调用 /token 端点,而不是 webclient。因此,服务器无法访问我的 localhost Oauth2 服务器。将我们的 Oauth2 服务器置于域名之后解决了问题。

现在,我可以连接现有用户,但不明白如何通过此插件登录新用户。
如果用户使用 oauth 登录,会收到一条错误消息,提示他在 Discourse 服务器上没有活动帐户。这很正常,因为这是一个新用户。

是否有专门的回调用于登录用户而不是注册用户?或者是否有特定的参数可以设置以允许创建帐户?

我的公司 oauth 服务器生成的 /profile JSON 响应中的一个字段有一个小拼写错误。修复拼写错误后一切都正常了。
但我不得不说 Discourse 的日志可能非常误导人!回调没有任何问题。

大家好:

我在从授权响应中提取用户 JSON 请求所需的 ID 时遇到问题。根据文档,似乎账户 ID 嵌套在数组中:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
   "access_token":"2YotnFZFEjr1zCsicMWpAA",
   "token_type":"Bearer",
   "expires_in":1800,
   "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
   "permissions":[
      {
        "accountId":123,
        "availableScopes":["contacts_view", "contacts_me",
"contacts_edit", "finances_view", "events_view"]
      }
   ]
}

我尝试将 oauth2 回调用户 ID 路径设置为 permissions[0].accountId,但我的 uid 值始终为空。不幸的是,提取用户 JSON 的调用需要在 JSON URL 中包含此 accountId。

我通过传递 permissions.first.accountId 成功解决了这个问题。我发现当我在测试属性中传递 permissions 时,该数组已被解析为 Ruby 数组。不幸的是,字段似乎拒绝了调用数组元素的 Ruby 语法,并且任何使用 Javascript 语法的尝试都会导致“TypeError String to Integer”错误。幸运的是,Ruby 有上述语法,这是预期的方法吗?

我刚用 Authentik OAuth2 实现了这个功能,但在 oauth2 user json url 设置上遇到了一些麻烦。我使用了 Authentik 的 user_info 端点(/application/o/userinfo/),但我不知道如何映射字段。对于任何想了解如何设置 Discourse 与 Authentik 的 OAuth2 的人,这里是总结:

  • 用户 ID 路径:preferred_username
  • 用户名路径:preferred_username
  • 姓名路径:name
  • 邮箱路径:email
  • 邮箱已验证路径:email_verified
  • 头像:空。

我遇到了以下问题:

  1. 一开始,我在 JSON URL https://DOMAIN/application/o/userinfo/ 中忘记了末尾的斜杠。这导致用户信息请求(源永久链接)返回 301 HTTP 状态码,导致登录失败。我不知道按规范是否应该有末尾的斜杠,但也许应该正确处理 301。
  2. 调试这个过程很棘手。oauth2 debug auth 设置非常有用,但是……Logster 会在实际转储有意义的响应数据之前截断调试日志。我不得不手动修改容器中的日志行:
    log("user_json_response: #{user_json_response.status} #{user_json_response.headers} #{user_json_response.body}")
    
    也许可以更新那行日志?我想这可以帮助其他人找出 JSON 属性路径。
4 个赞

我刚通过插件设置了 Auth0,发现头像没有被抓取。

以下是相关的设置:

  DISCOURSE_OAUTH2_ENABLED: true
  DISCOURSE_OAUTH2_CLIENT_ID: '${DISCOURSE_OAUTH2_CLIENT_ID}'
  DISCOURSE_OAUTH2_CLIENT_SECRET: '${DISCOURSE_OAUTH2_CLIENT_SECRET}'
  DISCOURSE_OAUTH2_AUTHORIZE_URL: '${DISCOURSE_OAUTH2_ISSUER}/authorize?connection=xxx&login_options=yyy'
  DISCOURSE_OAUTH2_TOKEN_URL: '${DISCOURSE_OAUTH2_ISSUER}/oauth/token'
  DISCOURSE_OAUTH2_USER_JSON_URL: '${DISCOURSE_OAUTH2_ISSUER}/userinfo'
  DISCOURSE_OAUTH2_SCOPE: 'email openid profile'
  DISCOURSE_OAUTH2_JSON_USER_ID_PATH: 'sub'
  DISCOURSE_OAUTH2_JSON_USERNAME_PATH: 'nickname'
  DISCOURSE_OAUTH2_JSON_NAME_PATH: 'name'
  DISCOURSE_OAUTH2_JSON_EMAIL_PATH: 'email'
  DISCOURSE_OAUTH2_JSON_EMAIL_VERIFIED_PATH: 'email_verified'
  DISCOURSE_OAUTH2_JSON_AVATAR_PATH: 'picture'
  DISCOURSE_OAUTH2_EMAIL_VERIFIED: true
  DISCOURSE_OAUTH2_OVERRIDES_EMAIL: true
  DISCOURSE_OAUTH2_ALLOW_ASSOCIATION_CHANGE: false

在调试日志中,我可以看到 JSON 响应中设置了 picture 元素,但用户的头像没有改变,无论是新用户还是现有用户。

我错过了什么?

如何用另一个图标或图像替换登录按钮上的图标是最佳方法?

.btn-social.oauth2_basic:before {
    content: url('https://www.contoso.com/path/to/image');
}

.btn-social.oauth2_basic > svg {
    display: none;
}

感觉足够了,但有点取巧

2 个赞

该插件似乎只在用户首次创建时更新头像/用户名,而不是在每次登录时更新。

有什么方法可以修复此问题,并在登录/重新连接时让插件也更新头像吗?

您可以使用 auth overrides emailauth overrides usernameauth overrides name 设置使这些内容在将来的登录中生效。恐怕我们目前没有类似的头像设置,但我们非常欢迎您提交拉取请求(pr-welcome)。

2 个赞

谢谢!我后来找到了这些。我 fork 了这个仓库,并添加了我自己的版本,使其能够与 Roblox 配合使用,其中包括头像的覆盖。我相信这只是使用了 DiscourseConnect 的头像覆盖,所以人们无法更改它。

我希望的一件事是 Roblox 不会在 OAuth 中提供电子邮件,所以我很遗憾需要让他们使用电子邮件注册。但这对于你们来说不是问题,哈哈。

帖子已拆分为新主题:Twitter 登录无法在 Meta 上使用

有人知道这个是否仍然有效吗?

是的。我相信这个插件能正常工作。 :+1:

1 个赞

您好,我已成功将此插件集成到我的 discourse discuss.frontendlead.com 中,我正在使用 teachable OAuth https://docs.teachable.com/docs/oauth-quickstart-guide

但是,我只想允许那些在 teachable 上拥有当前付费账户的人成功注册。我想象中,我需要在此插件中添加自定义功能来处理这个问题?我想知道,你们或者我自己是否可以,在 OAuth 之后在设置中引入另一个名为“自定义代码”的字段,允许开发人员在注册后执行特定操作?或者是否有更好的建议,请告诉我。

编辑:我 fork 了该仓库,并在以下位置使其正常工作:

如果其他使用 teachable 的人也在尝试做同样的事情,我的仓库将开箱即用,唯一的问题是如果您没有购买课程,它会提示您需要访问我的域名进行购买。您可能希望根据自己的用例更新此信息。

2 个赞

太棒了!

Discourse Patreon 插件的 OAuth2 注册也存在类似情况。当启用“使用 Patreon 登录”时,它允许任何拥有 Patreon 账户的人在 Discourse 网站上注册。网站所有者通常希望只允许 他们的 支持者注册 Discourse 账户。我想知道 Patreon 是否会返回允许将类似逻辑添加到 Patreon 身份验证中的详细信息?

1 个赞

我遇到了和上面 @qlands 完全一样的错误。

我最初的计划是将配置文件信息发送到 token 中。看到它不起作用,我将其剥离,缩进以尝试 JSON 方法。但它甚至没有到达调用 JSON 文件的地步。

错误消息是:

(oauth2_basic) 身份验证失败!invalid_credentials: OAuth2::Error, {
  "access_token":"fa79b6fe0763862f5a8fd8",
  "token_type":"Bearer",
  "expires_in":3600,
  "scope":"profile"
}

您认为上述回复有什么问题吗?
为什么 OAuth2 服务器回复了 200 并附带 token,而插件却生成了 invalid_credentials 错误?