将 Discourse 用作身份提供者(SSO,DiscourseConnect)

我能够使用它为我的 Minecraft 服务器创建一个帐户链接系统!我想分享一下它的样子!这是我第一次使用 Discourse SSO,所以我可能把一切都弄得太复杂了。不过,它能用,这才是最重要的。

4 个赞

您好,我已正确完成所有这些操作。但是,当用户未登录 Discourse 时,会显示用户登录弹出窗口。当我填写用户名和密码时,它不会将我重定向回 return_url。您能帮帮我吗?

我假设nonce是为了防止_重放攻击_。我在网上读到,使用HTTPS时重放攻击是不可能的,而我正在使用HTTPS。那么我还需要使用nonce吗?我之所以这么问,是因为我不确定把它存放在哪里。把它作为用户浏览器中的一个安全、明文的cookie来存储,然后与返回的有效负载一起从浏览器中读取,这样有意义吗?

这个从原始帖子链接过来的库 GitHub - ArmedGuy/discourse_sso_node: npm package for Discourse SSO login features. 在验证用户时并不使用nonce

是的,你仍然需要验证 nonce,因为它能防止重用 Discourse 在将用户重定向回你的站点时发送的载荷。

例如,假设你的站点有一些内容是付费的,只有 Discourse 中 subscribers 组的成员才能访问,并且你使用了 Discourse 发送到你站点的载荷中的 groups 字段来仅向 subscribers 组的成员显示付费内容。如果你不验证 nonce,一个不再是 subscribers 组成员的用户就可以使用他曾经是成员时的一个旧载荷来登录你的站点并查看付费内容。

最好将 nonce 存储在数据库中,并设置一个较短的过期时间,一旦使用就从数据库中删除 nonce。但是,如果你无法使用数据库,那么你可以使用 cookie 来存储 nonce,但你需要执行一些额外的步骤来防止载荷重用:

  1. 在生成 nonce 时为其附加一个过期时间,例如从当前时间起 10 分钟。
  2. 对整个 cookie(nonce + 过期时间)进行签名,以防止用户修改 nonce 和/或过期时间。
  3. 验证 cookie 的签名并确保 nonce 没有过期。

这样应该能提供足够好的防止载荷重用的保护。请记住,从技术上讲,重用载荷仍然是可能的,但会限制在 10 分钟的窗口内,而不是永远。

一个更简单的解决方案,不需要 cookie,就是在你生成的载荷中包含一个 自定义字段 来表示过期时间。然后,当 Discourse 将用户重定向回你的站点并附带载荷时,你的自定义字段将包含在其中,你可以检索过期时间并验证它是否已过期。要将自定义字段包含在载荷中,你需要包含一个以 custom. 为前缀的字段,所以你的载荷看起来会像这样:

nonce=NONCE&return_sso_url=RETURN_URL&custom.expiration_date=TIMESTAMP
4 个赞

您也可以将 nonce 存储在会话中,这样也可以防止用户篡改它。

3 个赞

多年后再次回到这个帖子

有人能告诉我(@pfaffman@tobiaseigen@iamntzDiscourse SSO 提供商返回什么吗?我知道我可以“试试看”,但最好有文档记录。GitHub PHP 示例代码中甚至没有真正提到其他字段。

理想情况下,它应该发送与 Discourse 使用外部脚本进行 SSO 时相同的字段,例如外部 ID、电子邮件、用户名、姓名、头像照片等。这样我们就可以导入这些信息并在我们这边创建用户!

它还会将电子邮件告知 WordPress 吗?

关于群组、徽章等呢?我们可以通过发出 REST 调用找到这些信息吗?

最后,用户的私人消息和其他东西怎么样?我猜如果 Discord 是一个 oAuth 提供商并允许我们的应用程序使用这些东西,那将是太棒了。

启用 Discourse Connect 时,我收到此错误:
enable_discourse_connect: 您不能同时启用 DiscourseConnect 和仅限邀请。

有什么想法吗?

我看到您在这里问了同样的问题:Setup DiscourseConnect - Official Single-Sign-On for Discourse (sso) - #537 enable discourse connect 设置而不是 enable discourse connect provider 设置,那么另一个主题是询问您问题的正确地方。

enable discourse connect provider 设置用于当您想将 Discourse 站点用作另一个站点的身份提供者时。enable discourse connect 设置用于当您想通过外部站点将用户登录到 Discourse 时。

1 个赞

我为我正在构建的一个 Flask 应用程序实现了 Python 过程。这里有一些样板代码供需要的人使用。本主题中概述的步骤非常简单易懂,但我不是安全专家,所以如果我忽略了任何内容,请告诉我!

https://gist.github.com/ScottMastro/011b7a823177ae9022aac35cee

2 个赞

我们正尝试使用 Discourse 作为 SSO 提供商进行实现,但不明白 Discourse 如何知道需要验证哪个用户?说明中写道:“创建一个包含 nonce 和 return url 的新 payload”。但是,当您通过 fetch 将此发送到 Discourse 时,Discourse 如何知道要检查哪个用户是否已登录?抱歉,如果这听起来像个愚蠢的问题,但我就是无法理解这是如何工作的,而且我多年来接触过很多身份验证系统,所以还算熟悉。需要检查登录状态的用户电子邮件是否需要包含在发送到 Discourse 的 payload 中?如果是,需要发送到 Discourse 的 payload 的确切结构是什么?如果不是,Discourse 到底在检查什么?我的假设是我们这边向用户索要他们的电子邮件,然后将包含电子邮件的 payload 发送给 Discourse,以查看该特定用户是否已登录,但这与说明不符,所以我完全感到困惑。感谢您的任何帮助。

没关系。我们已经解决了。我们曾认为 SSO URL 需要以 POST 请求的形式发送到 Discourse 实例,然后接收响应。现在我们知道这是一个重定向到 Discourse,然后 Discourse 会重定向回我们的网站。所以现在很清楚该怎么做了。抱歉之前的帖子。

3 个赞

FYI/FWIW:我提交了一个 PR,允许在身份验证请求中使用 prompt=none 参数。这类似于 OpenID Connect 协议中的一项功能,它允许 SSO 消费者探测用户/客户端是否已登录,而无需在用户未登录时将其发送到登录对话框。

该 PR 已由 Discourse 团队的某人评审了大约 8 周,似乎比我预期的要长。:crying_cat_face:

7 个赞

您好 @mdoggydog - 很抱歉这么长时间才回复!

我刚刚审核并合并了 PR - 感谢您的贡献!:raised_hands:

3 个赞

太好了!谢谢你,@david

如我所承诺的,我刚刚在此更新了维基文章,以包含新参数的说明(以及早先的 logout 参数),并修复了一些小的拼写/语法错误,以及添加了一个参考部分,记录了我从源代码中了解到的 sso= 负载。

2 个赞

我想停止使用我们的网站作为 Discourse 的 SSO,而是使用 Discourse 内置的登录工具来限制对我们网站上某些内容的访问。

我认为合适的工具是:GitHub - discourse/discourse-auth-proxy: An http proxy that uses the DiscourseConnect protocol to authenticate users

我还没有找到关于如何使用它的详细说明。

我可以在与我们的 Discourse 站点相同的 DigitalOcean 虚拟机上安装它,还是需要将其托管在其他地方?

编辑:已将我的问题加粗 :slight_smile:

1 个赞

上面问题的任何帮助?Use Discourse as an identity provider (SSO, DiscourseConnect) - #148 by alehandrof

我将 return_sso_url 设置为一个本身带有查询参数的 URL:

http://localhost:7000/completeLogin?returnto=%2F

我发送到 /session/sso_provider 并作为 sso 参数的载荷在 base64 编码前看起来是这样的:

nonce=ENIwf0bElViDu325dTd6&return_sso_url=http://localhost:7000/completeLogin?returnto=%2F

身份验证后 Discourse 实际重定向到的 URL 是这样的(ssosig 参数已缩写):

http://localhost:7000/completeLogin?returnto=/\u0026sso=...\u0026sig=...

令我惊讶的是,我为 return_sso_url 设置的查询字符串似乎被 某个东西 URL 解码了,因为它显示的是 returnto=/ 而不是 returnto=%2F。在 base64 解码 sso 后,我在其中找到的 return_sso_url 的值也显示为斜杠而不是 %2F

这是我应该预料到的吗?(如果是,为什么?)这是 Discourse 的一个 bug 吗?

sso 载荷中包含 avatar_url 而不是 /u/{username}.json/session/current.json 中返回的 avatar_template 的原因是什么?

对于未设置头像的用户,avatar_url 不存在,而 avatar_template 包含 Discourse 用于显示这些用户头像的 leter_avatar_proxy 路径,并且对于已设置头像的用户,avatar_url 指向原始头像图像,而不是缩放到所需大小的图像。

在我看来,任何打算使用 sso 中包含的头像信息的人都会想要 avatar_template——但之后需要进行额外的 API 请求才能获得它。

2 个赞

我现在正在我的应用程序中实现 SSO,到目前为止登录效果很好,但注销不行。

我的 Discourse 实例正在正确重定向回 return URL,没有任何 sso 或 sig 参数,但当我打开 Discourse 时,我的帐户仍然处于登录状态。

有什么想法吗?

我假设您正在使用 Discourse 的 logout redirect 站点设置,以便在用户注销 Discourse 后将他们重定向回您的应用程序。

问题的一个可能原因是您的 Discourse 站点启用了 login required 设置。当启用该设置时,如果用户直接访问 Discourse 站点,Discourse 会自动将未经身份验证的用户重定向到 SSO 提供商站点。这意味着,除非您在用户首次重定向到 logout redirect URL 时注销用户在您的应用程序中的登录状态,否则下次访问该站点时,他们将自动登录 Discourse。您可以通过在浏览器检查器打开其网络选项卡的情况下完成此过程来确认此行为。

以防万一有用,以下是 WP Discourse 插件处理 Discourse 注销重定向的方式:wp-discourse/lib/sso-provider/discourse-sso.php at main · discourse/wp-discourse · GitHub

2 个赞