37

我在不同域中有多个站点:example.comexample.org和. 所有网站都具有共同的外观和感觉,并且应该共享相同的用户群。mail.example.compassport.example.org

在这种极端情况下,我仍然希望所有站点透明地(尽可能)共享具有以下关键属性的用户会话:

  1. 单点登录。当用户passport.example.org登录并访问任何其他网站时——他应该被视为已登录。

    登录的用户会$username在网站标题和不同的导航菜单中看到“你好”问候语,列出他们可以访问的服务。如果他没有登录,则会出现一个“登录”链接,而不是问候,指向passport.example.org/signon

    受信任域的列表是已知的,因此无论是使用 OpenID 还是使用一些自制的轻量级协议来实现都相当简单。当用户第一次访问该站点时,我会将他重定向到位于 的特殊身份验证端点passport.example.org,然后它会默默地将他重定向回来,其中包括身份信息(或“未登录”匿名身份)。对于大多数浏览器来说,这是完全透明的。显然,我使用 nonce 值来对抗重定向循环。

  2. 单签。当用户在下次访问任何站点时单击任何站点标题中的“注销”时 - 他应该被视为“未登录”。

    OpenID 不是为此而设计的。我目前的想法(我已经有一个部分工作的实现)不是发送用户身份,而是发送“全局”会话令牌并在数据库中共享全局会话表(global_session_token ↔ 用户关系)。

  3. 机器人和无 cookie 用户支持. 网站有公共区域,用户代理应该可以在没有任何 cookie 支持的情况下访问这些区域。

    正因为如此,我在 (1) 中提到的重定向成为一个问题,因为对于每个单独的页面请求,我最终都会将用户代理扔到身份验证端点并返回。这不仅会使机器人感到困惑,而且会很快用出生时死掉的会话污染我的会话数据库。而且我绝对不想显示“嘿,你没有启用 cookie,走开!” 页面,那将是非常粗鲁和令人失望的。虽然我需要 cookie 支持才能登录,但我希望用户可以自由阅读网站的用途等等——没有任何限制。

    除了我提到的一些透明的跨域重定向之外,我明确不想将会话 ID 放在 URL 中。我相信这样做是一个安全问题,而且通常是一件坏事。

    在这里,我几乎没有想法。

好的,我知道这很难,但 Google 实际上以某种方式使用 ( google.comgoogle.很多 gTLD等等gmail.com),对吗?所以这应该是可能的。

我将感谢协议描述想法(那将是最好的)或系统链接(阅读代码或只是观看和学习的实时站点)已经成功实现了这样的东西。

总结一下:几个没有共同根的域,共享用户群,单点登录,单点注销,匿名浏览不需要cookie。

所有站点都在同一个网络上(但位于不同的服务器上)并部分共享同一个 PostgreSQL 数据库(位于同一数据库的不同方案中)。大多数网站都是用 Python/Django 编写的,但其中一些网站使用 PHP 和 Ruby on Rails。虽然我正在考虑一些与框架和语言无关的东西,但我很感激指出任何实现。即使我无法使用它们,如果我知道它是如何在那里完成的,也许我将能够实现类似的东西。

4

7 回答 7

31

那么,让我进一步解释一下。(所有 URL 都是虚构的!)正如我所说,访问者转到http://www.yourwebpage.com并表示他想登录。他被重定向到http://your.loginpage.org?return=http: //www.yourwebpage.com/Authenticated他必须提供他的用户名和密码。
当他的帐户信息有效时,他将返回登录 URL 中提供的页面,但带有一个将用作 ID 的附加参数。因此,他访问http://www.yourwebpage.com/Authenticated?ID=SharedSecret,其中 SharedSecret 将是一个临时 ID,有效期为 30 秒或更短。
当您的身份验证页面被调用时,该页面将调用一个在 yourwebpage.com 和 loginpage.org 之间共享的方法,以查找 SharedSecret 的帐户信息以检索更永久的 ID。此永久 ID 存储在 yourwebpage.com 的网络会话中,绝不应向用户显示。
共享方法可以是任何东西。如果两台服务器都在同一台机器上,它们就可以访问同一个数据库。否则,它们可能会通过 Web 服务与另一台服务器通信。这将是服务器到服务器的通信,因此用户是机器人还是没有 cookie 支持并不重要。这部分不会被用户注意到。
您唯一需要处理的是用户的会话。通常,会向用户发送一个会话 ID,该会话 ID 存储在 cookie 中,但它也可以作为 GET 请求的一部分作为 URL 的一部分。但是,通过在表单中​​添加隐藏的输入字段,在 POST 请求中包含会话 ID 会更安全一些。

幸运的是,一些 Web 开发语言已经提供了会话支持,因此您甚至不必担心维护会话和发送会话 ID。不过,这项技术很有趣。而且您需要注意会话应该始终是临时的,因为会话 ID 存在被劫持的风险。

如果您必须处理不同域上的多个站点,那么您将需要首先进行一些服务器到服务器的通信。最简单的方法是让他们共享同一个数据库,但最好围绕这个数据库构建一个 Web 服务,以获得额外的保护。确保此 Web 服务仅接受来自您自己域的请求,以增加更多保护。
当您有服务器到服务器的连接时,用户将能够在您的域之间切换,并且只要您将会话 ID 传递给新域,用户就会登录。如果用户正在使用cookie,会话丢失的可能性不大,需要重新登录。如果没有 cookie,如果会话 ID 在浏览页面之间丢失,用户可能必须再次登录才能获得新的 cookie。(例如,访问者访问 Google,然后返回您的站点。使用 cookie,可以从 cookie 中读取会话。没有 cookie,会话将丢失,因为 Google 不会转发会话 ID。

请记住,在不同域之间传递会话 ID 是一种安全风险。会话 ID 可以被劫持,从而使其他人有可能冒充您的访问者。因此,会话 ID 应该是短暂的和模糊的。但即使黑客获得了会话 ID 的访问权限,他仍然无法完全访问帐户本身。他将无法拦截服务器到服务器的通信,因此他无法使用您的用户信息访问数据库,除非他直接进入登录页面。

于 2009-06-29T08:33:38.137 回答
5

AFAIK,谷歌只是为“Google.com”域使用了一个 cookie。但谷歌也使用允许通用登录机制的 OpenID。基本上,这是通过将您重定向到一个特殊的登录页面来实现的。此登录页面将检测您是否已登录,如果您未登录,它将要求您登录。否则,它只会将您直接重定向到下一页。

因此,在您的情况下,用户将打开 somepage.example.com 并且此应用程序的会话没有登录 ID。因此,它会将用户重定向到用户将登录的 login.example.biz。此页面后面也将是一个会话,并且该会话将告诉用户已经登录。(或者不是,在这种情况下用户必须首先登录。)然后它重定向用户 somepage.example.com?sessionid=something 这个 sessionid 将被存储在 somepage.example.com 的会话中。然后这个会话也将知道用户已经登录并且对于用户来说它几乎是透明的。

实际上,用户被重定向了两次。

于 2009-06-25T11:18:14.560 回答
1

你在使用 ASP.NET 吗?如果是这样,您可能想查看enableCrossAppRedirects属性。

于 2009-06-25T10:47:22.360 回答
1

如果您的所有应用程序都在一个域上,那么这并不太难,因为您可以使用域级别的 cookie 来处理会话控制。(无cookie的会话管理很困难,但可以做到,但很难。)

但是,您指定了 example.com 域上的一些站点,以及 example.org 域上的一些站点。

在我的 google sigh-in 和他们的 orkut.com 的其他网站上玩了一下,看起来当您点击需要凭据的页面时,它会将您重定向到用于帐户登录的公共网站,然后将您重定向回原始网站站点,大概在 URL 中传递了某种会话令牌。据此推测,orkut.com 服务器直接与 google.com 服务器协商以验证令牌并获取所需的任何其他用户信息。

请求的域级 Cookie 的更多信息

如果你有两个站点,比如说foo.example.combar.example.com,你可以设置一个特定于主机的 cookie,但你也可以为域设置一个 cookie,该域上的所有主机都可以看到。

所以,foo.example.com可以foo.example.com专门为它设置一个cookie,它只会被自己看到,但它也可以为域设置一个cookie,example.com,当用户访问时,bar.example.com他们也会看到第二个cookie。

但是,如果您还有一个站点,snafu.example.org,它就看不到foo设置的这个域级别的 cookie,因为example.orgexample.com是两个完全不同的域。

您可以使用域级别的 cookie 来维护同一域中站点之间的会话信息。

您如何设置域级别的 cookie 取决于您的开发环境(我没有使用 rails 的经验,抱歉)。

于 2009-06-26T02:12:07.857 回答
1

对于此解决方案,不需要护照服务器。

登入

  1. 登录
  2. 使用加密的会话 ID 和其他信息创建令牌
  3. 显示带有来自所有域的令牌的 img 以在其上设置 cookie。

通过cookie授权

  1. 您已经在所有域上都有 cookie。

登出

  1. 清除 cookie
  2. 销毁会话
  3. 清除与数据库中最后一个会话 ID 的关系用户 ID(我认为您将会话 ID 保存在用户表中以通过 cookie 建立会话)

我不能尝试这个解决方案。但现在我和你有同样的问题(SSO),我明天试试这个。

于 2009-07-08T23:13:40.863 回答
0

对于 SSO 场景和联合身份,我都使用了 shibboleth,但我假设您需要比上面提到的更简单的解决方案。

于 2009-09-20T00:43:03.177 回答
-4

一个支持跨域的 Rails 插件会很棒。

我想这样做,我能想到的唯一方法是强制用户下载工具栏,或者一些可以为我自动处理登录的小型空中应用程序。

我很想知道另一种方式,因为它吹

于 2010-03-11T04:43:31.117 回答