Discourse 同步登录问题


(DaBin) #1

Discourse sso 同步登录实现

背景/条件:

  1. 主站: http://mysite.com (不是真实的)
    论坛: http://discourse.mystie.com
  2. 主站服务器技术栈: flask + python3 (不限制,只是用的 工具和方法 会有所不同)
      论坛服务器技术栈: rails + ruby (Discource 源码)
  3. 主站已实现: 根据论坛返回的 sso 和 sig, 解密后,配合用户信息加密生成新的相应可用的 sso 和 sig,组成附带登录状态信息的论坛登录 url (sso_login_url)
    例如: http://discourse.mysite.com/session/sso_login?sso=xxx&sig=xxx&return_path=/
    (即 sso 的基本必须方法) 称为: general_payload_url 方法!!!
    参考: Discourse 单点登录功能

实现目标:

sso 登录实现同步登录/注销

  1. 论坛登录的同时,主站同步登录 (sso 跳转到主站登录页面并返回)
  2. 论坛注销的同时,主站同步注销 (sso 跳转到主站注销页面并返回)
  3. 主站登录的同时,论坛自动登录 (不跳转到论坛)
  4. 主站注销的同时,论坛自动注销 (不跳转到论坛)

关键参数说明:

  1. _t : cookie 中的键值,即用户 token,由 ruby::SecureRandom 生成的一个16位随机数。
    • 作用: 论坛登录后,会自动生成,存在浏览器 cookie 中,只要不退出登录,可以复制它的值到其他地方(浏览器), 写入到 cookie,就可以登录。
    • 如果这个安全问题不影响大碍,那么这就可以利用起来。

前期准备:

  1. 主站供论坛 sso 登录页面( 主站 login 页面) http://mysite.com/login (也可以修改 html 元素,在论坛创建登录的对话框,仅供参考) 在 /admin 页面设置 sso_url 和 logout_url,开启 sso
  2. 主站供论坛注销时重定向的注销页面( 主站 logout 页面) http://mysite.com/logout
  3. 将论坛 cookie 的 _t 字段的 domain (所属域名) 改为 mysite.com
    • 作用: 那么论坛和主站就可以共享这个 _t 字段了!这时实现同步登录的关键!!涉及 二级域名和一级域名共享 cookie 的问题
    • (可以看一下 https://segmentfault.com/a/1190000006932934)
    • 修改源码:
cd /var/discourse (discourse 代码存放目录)
./launcher enter app
cd lib/auth/
vim default_current_user_provider.rb

162 行后面加上一个逗号: ,
162163 行之间新加一行 domain: 'mysite.com
修改后代码: (158 - 164 行)

hash = {
      	value: unhashed_auth_token,
     	httponly: true,
     	expires: SiteSetting.maximum_session_age.hours.from_now,
     	secure: SiteSetting.force_https,
      	domain: "mysite.com"
    	}

设计思路:

1. 论坛登录

论坛点击登录,跳转到主站 http://mysite.com/login, 附带 sso 和 sig 参数信息(实际跳转到 http://mysite.com/login?sso=xxx&sig=xxx)
操作: 用户输入登录信息( 用户名/密码 )进行登录后,调用 general_payload_url 方法,重新生成新的 sso 和 sig,组成论坛登录 url (sso_login_url),跳转过去。

2. 主站登录

主站点击登录,用户输入登录信息进行登录后,想方法生成并获取 cookie 的 _t 字段 (浏览器不跳转到论坛)

操作:

  1. 主站服务器后台访问 http://discourse.mystie.com/session/sso,论坛会自动重定向到 login 页面 http://mysite.com/login,附带 sso 和 sig 参数信息
res = requests.get("http://discourse.mystie.com/session/sso", timeout=10)
sso_url = res.url  # sso_url = http://mysite.com/login?sso=xxx&sig=xxx
  1. 这时调用 general_payload_url 方法,生成新的论坛登录 url (sso_login_url)
    • python 代码
sso_login_url = general_payload_url(sso_url)  
# sso_login_url = http://discourse.mysite.com/session/sso_login?sso=xxx&sig=xxx&return_path=/
  1. 使用可以获取 cookie 的方法后台访问 这个论坛登录 url (sso_login_ur),那么就可以从 cookie 中获得 _t 这个字段的值
    • python 代码:
import urllib.request
import http.cookiejar

def get_cookie_t(sso_login_url):
    cookie = http.cookiejar.CookieJar()
    handler = urllib.request.HTTPCookieProcessor(cookie)
    opener = urllib.request.build_opener(handler)
    response = opener.open(sso_login_url, timeout=10)
    _t = None
    for item in cookie:
        if item.name == '_t':
            _t = item.value
            break
    return _t
  1. 将 _t 写进浏览器 cookie 中,设置 domain 为 mysite.com , 那么论坛就同步登录了。

3. 论坛注销

论坛点击注销,跳转到主站 http://mysite.com/logout

操作: 主站注销用户,并删除浏览器 cookie 中的 _t 字段,返回(论坛)。不删除 _t 会出错!

4. 主站注销

站点击注销 (浏览器不跳转到论坛)

操作: 注销用户后,删除 cookie 中 _t 字段,那么论坛也同步注销了。


(秀川大漠) #2

我也需要这个功能。。。。


(秀川大漠) #4

去年用DZ 做过。 不是跨域。(我不是技术,找别人做的…)


(秀川大漠) #6

期待,
说不定要你帮忙 。


(DaBin) #7

Discourse sso 同步登录实现

背景/条件:

1、 主站: http://mysite.com (不是真实的)
  论坛: http://discourse.mystie.com
2、 主站服务器技术栈: flask + python3 (不限制,只是用的 工具和方法 会有所不同)
  论坛服务器技术栈: rails + ruby (Discource 源码)
3、 主站已实现: 根据论坛返回的 sso 和 sig, 解密后,配合用户信息加密生成新的相应可用的 sso 和 sig,组成附带登录状态信息的论坛登录 url (sso_login_url)
   例如: http://discourse.mysite.com/session/sso_login?sso=xxx&sig=xxx&return_path=/
  (即 sso 的基本必须方法) 称为: general_payload_url 方法!!!
   参考: Discourse 单点登录功能

实现目标:

sso 登录实现同步登录/注销
1、 论坛登录的同时,主站同步登录 (sso 跳转到主站登录页面并返回)
2、 论坛注销的同时,主站同步注销 (sso 跳转到主站注销页面并返回)
3、 主站登录的同时,论坛自动登录 (不跳转到论坛)
4、 主站注销的同时,论坛自动注销 (不跳转到论坛)

关键参数说明:

1、_t : cookie 中的键值,即用户 token,由 ruby::SecureRandom 生成的一个16位随机数。
  作用: 论坛登录后,会自动生成,存在浏览器 cookie 中,只要不退出登录,可以复制它的值到其他地方(浏览器), 写入到 cookie,就可以登录。
  如果这个安全问题不影响大碍,那么这就可以利用起来。

前期准备:

  1、主站供论坛 sso 登录页面( 主站 login 页面) http://mysite.com/login (也可以修改 html 元素,在论坛创建登录的对话框,仅供参考) 在 /admin 页面设置 sso_url 和 logout_url,开启 sso
  2、主站供论坛注销时重定向的注销页面( 主站 logout 页面) http://mysite.com/logout
  3、将论坛 cookie 的 _t 字段的 domain (所属域名) 改为 mysite.com
  作用: 那么论坛和主站就可以共享这个 _t 字段了!这时实现同步登录的关键!!涉及 二级域名和一级域名共享 cookie 的问题
  (可以看一下 https://segmentfault.com/a/1190000006932934)
   修改源码:

cd /var/discourse (discourse 代码存放目录)
./launcher enter app
cd lib/auth/
vim default_current_user_provider.rb

  在 162 行后面加上一个逗号: ,
  在 162163 行之间新加一行 domain: ‘mysite.com
  修改后代码: (158 - 164 行)

hash = {
      	value: unhashed_auth_token,
     	httponly: true,
     	expires: SiteSetting.maximum_session_age.hours.from_now,
     	secure: SiteSetting.force_https,
      	domain: "mysite.com"
    	}

设计思路:

1、论坛登录: 论坛点击登录,跳转到主站 http://mysite.com/login, 附带 sso 和 sig 参数信息(实际跳转到 http://mysite.com/login?sso=xxx&sig=xxx)
  操作: 用户输入登录信息( 用户名/密码 )进行登录后,调用 general_payload_url 方法,重新生成新的 sso 和 sig,组成论坛登录 url (sso_login_url),跳转过去。

2、主站登录: 主站点击登录,用户输入登录信息进行登录后,想方法生成并获取 cookie 的 _t 字段 (浏览器不跳转到论坛)
  操作:
  a. 、主站服务器后台访问 http://discourse.mystie.com/session/sso,论坛会自动重定向到 login 页面 http://mysite.com/login,附带 sso 和 sig 参数信息
   (http://mysite.com/login?sso=xxx&sig=xxx)
   python 代码:

res = requests.get("http://discourse.mystie.com/session/sso", timeout=10)
sso_url = res.url  # sso_url = http://mysite.com/login?sso=xxx&sig=xxx

  b、这时调用 general_payload_url 方法,生成新的论坛登录 url (sso_login_url)
  python 代码

sso_login_url = general_payload_url(sso_url)  
# sso_login_url = http://discourse.mysite.com/session/sso_login?sso=xxx&sig=xxx&return_path=/

  c、使用可以获取 cookie 的方法后台访问 这个论坛登录 url (sso_login_ur),那么就可以从 cookie 中获得 _t 这个字段的值
  python 代码:

import urllib.request
import http.cookiejar

def get_cookie_t(sso_login_url):
    cookie = http.cookiejar.CookieJar()
    handler = urllib.request.HTTPCookieProcessor(cookie)
    opener = urllib.request.build_opener(handler)
    response = opener.open(sso_login_url, timeout=10)
    _t = None
    for item in cookie:
        if item.name == '_t':
            _t = item.value
            break
    return _t

  d、将 _t 写进浏览器 cookie 中,设置 domain 为 mysite.com , 那么论坛就同步登录了。

3、论坛注销: 论坛点击注销,跳转到主站 http://mysite.com/logout
  操作: 主站注销用户,并删除浏览器 cookie 中的 _t 字段,返回(论坛)。不删除 _t 会出错!

4、主站注销: 主站点击注销 (浏览器不跳转到论坛)
  操作: 注销用户后,删除 cookie 中 _t 字段,那么论坛也同步注销了。


(杰瑞米大魔王) #9

@DaBin 你好,我看你的方案里面说论坛注销,跳转到主站,这一步是怎么实现的?是该源代码吗,还是有相应的API可以使用


(Kavinbright) #10

@DaBin 请问老铁,你的登出是怎么实现的。我现在需要实现在dissourse登出,主站也随之登出。多谢


(DaBin) #11

这是 discourse 自带的:
在管理页面 admin 点击设置—用户,有一个栏目叫 logout redirect,官方解释:登出后重定向至的地址。(如:http://somesite.com/logout)

那就可以设置为主站的一个登出页面了~


(DaBin) #12

设置–用户–logout redirect
设置退出跳转的页面


(杰瑞米大魔王) #13

谢谢!这个设置好了,整个流程都可以跑通了:+1:


(Erick Guan) #14

我把这个帖子合并到首贴去了。