将Discourse SSO与现有的Devise Rails网站集成

21
我有一个现有的Rails应用程序,使用devise作为用户身份验证。我添加了一个Discourse论坛,一切顺利,并且它位于子域名上。我已经阅读了https://meta.discourse.org/t/official-single-sign-on-for-discourse/13045上的帖子,但仍然不知道在现有的Rails网站上登录后该怎么处理devise方面的事情。目前这是我理解的流程:

步骤1:用户访问子域名上的Discourse论坛。用户需要登录,因此点击登录按钮。

步骤2:用户被发送到现有的Rails网站上的登录页面。

步骤3:用户在Rails网站上登录。

步骤4:用户应该被重定向到已登录的Discourse论坛子域名。

我的问题是-当用户在第3步登录时,我需要做什么才能使他们被重定向回子域名?有人成功实现了吗?我在那个教程页面上看到了这段代码片段:

  class DiscourseSsoController < ApplicationController
  def sso
    secret = "MY_SECRET_STRING"
    sso = SingleSignOn.parse(request.query_string, secret)
    sso.email = "user@email.com"
    sso.name = "Bill Hicks"
    sso.username = "bill@hicks.com"
    sso.external_id = "123" # unique to your application
    sso.sso_secret = secret

    redirect_to sso.to_url("http://l.discourse/session/sso_login")
  end
end

这是我需要在现有的Rails应用程序中添加的内容吗?我猜测解析器会检查URL中是否有该信息,如果有,则在完成设备登录过程后重定向,否则它将像往常一样工作。我应该把这段代码放在设备文件的哪个位置?


2
你最后解决了这个问题吗? - Daniel Hollands
1
你的问题有任何更新吗? - Kenny Meyer
2个回答

41
这很简单。根据https://meta.discourse.org/t/official-single-sign-on-for-discourse/13045的说明并稍作推断,我已经使其工作:
1)将参考实现https://github.com/discourse/discourse/blob/master/lib/single_sign_on.rb放入#{Rails.root}/lib目录中。
2)在routes.rb中添加此路由。
get 'discourse/sso' => 'discourse_sso#sso'

3) 将此控制器放置在您的app/controllers目录中

require 'single_sign_on'

class DiscourseSsoController < ApplicationController
  before_action :authenticate_user! # ensures user must login

  def sso
    secret = "MY_SECRET_STRING"
    sso = SingleSignOn.parse(request.query_string, secret)
    sso.email = current_user.email # from devise
    sso.name = current_user.full_name # this is a custom method on the User class
    sso.username = current_user.email # from devise
    sso.external_id = current_user.id # from devise
    sso.sso_secret = secret

    redirect_to sso.to_url("http://your_discource_server/session/sso_login")
  end
end

4) 在Discourse中设置SSO配置,需要如下:

sso url: http://your_rails_server/discourse/sso
sso secret : what you set as MY_SECRET_STRING above

5) 在Discourse中禁用其他登录类型。

6) 尝试在Discourse中登录。应该可以成功...


request.query_string为什么变成了nil?它是从哪里来的?你能帮我弄清楚为什么吗?我已经按照你的回复进行操作了。 - kamal
@DanSingerman,我们现有的Rails应用程序中应该首先访问哪个路由?我目前正在访问http://localhost:3000/discourse/sso,但在生成有效载荷时出现错误。 - kamal
@kamal 在尝试登录 Discourse(还要带一堆加密的 URL 参数)后,应该会命中这个。 - DanSingerman
大家好,你们能否帮忙详细说明一下如何在本地开发中使这个工作起来?如何配置子域名的Disourse论坛与顶级域名在开发中?请大家帮忙。谢谢。 - Sinal
1
使用更新版本的Rails,你还需要在重定向方法中传递 allow_other_host: true 参数。 - Octopussy
显示剩余2条评论

0

感谢 @DanSingerman

自您发布答案以来,它们已进行了更新。

  1. 现在的控制器
    class DiscourseSsoController < ApplicationController
      def sso
       secret = "MY_SECRET_STRING"
       sso = DiscourseApi::SingleSignOn.parse(request.query_string, secret)
       sso.email = "user@email.com"
       sso.name = "Bill Hicks"
       sso.username = "bill@hicks.com"
       sso.external_id = "123" # unique id for each user of your application
       sso.sso_secret = secret

       redirect_to sso.to_url("http://l.discourse/session/sso_login")
      end
    end
  • 安装Discourse API宝石或复制SingleSignOn类到您的lib文件夹中。此类在gem repo中:https://github.com/discourse/discourse_api/blob/main/lib/discourse_api/single_sign_on.rb

  • 关于query_string:如果您在本地测试,则应模拟来自Discourse的请求,因为它将包含一个带有2个参数(有效负载和sig)的查询:

    https://somesite.com/sso?sso=PAYLOAD&sig=SIG


  • 网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接