SSO(单点登录)是如何工作的?

36

我试图理解单点登录(SSO)的概念。据我所知,SSO允许您登录一次并访问多个应用程序(如果您有权限)。 因此,我登录应用程序A,建立一个令牌。那么令牌如何可用于应用程序B,以便我不必再次登录应用程序B(假设用户具有对A和B的权限)?我的应用程序是AngularJs应用程序。 我使用.Net WebApis访问数据。

我可以看到,如果我从应用程序A登录并检索令牌,然后通过将令牌传递给应用程序B启动应用程序B,这样应用程序B就具有了令牌,并且可以将其发送到服务器以确保用户有权访问B。但是,如果用户直接打开浏览器并访问应用程序B,那么他们的会话如何使用现有令牌建立?

如果答案是后端服务器上有会话状态,那么会话状态如何将应用程序A中已登录的用户与应用程序B的新请求匹配?

谢谢。


4
这实际上是您在谷歌搜索标题时的第一个结果:https://auth0.com/blog/2015/09/23/what-is-and-how-does-single-sign-on-work/ - thebjorn
3
@thebjorn 我已经阅读了第一个链接大约20次,但仍然不理解服务器是通过什么机制意识到浏览器已经登录,这可能是因为这篇文章是针对普通公众而非程序员撰写的。下面的回答立刻让我明白了一切归功于HTML5本地存储使所有工作都得以实现,但这是否也意味着使用SSO必须要使用JS? - Timo Huovinen
@TimoHuovinen,你不需要本地存储/JS。认证/SSO/登录服务器以正常方式登录用户(使用会话/cookie/甚至本地存储,只要它能在下次访问登录服务器时确定用户已登录)。当客户端服务器需要用户在显示页面之前登录时,它不会呈现登录表单,而是重定向到登录服务器。由于登录服务器知道用户已登录,因此它发送回一条消息,说“这是用户123”,由于客户端服务器信任登录服务器,因此无需密码即可在本地登录用户123。 - thebjorn
@TimoHuovinen..显然,登录服务器的消息需要进行安全通信。一种方法是加密消息并将其作为重定向中的get参数发送(这很简单,但会向用户披露消息)。或者我们只需发送一个“令牌”,即唯一的随机值。然后客户端服务器需要直接联系登录服务器(即在浏览器之外的服务器对服务器)并说“我有这个令牌,你能给我数据吗?”如果登录服务器识别该令牌,则会发送“这是用户123”,客户端服务器将无需密码即可登录该用户。 - thebjorn
@thebjorn,所以如果他没有在应用程序上登录,它将重定向并自动登录用户到登录服务器。我非常感谢您的反馈,知道JS不是强制性的会再次改变我的理解(实际上,所有的解释都非常令人困惑,除非你已经理解了这个概念)。 - Timo Huovinen
@TimoHuovinen 没错 :-) 应用程序会重定向任何未登录的用户,并登录(无需密码)从登录服务器进入的所有用户 - 就是这样。 登录服务器立即将已经登录的用户重定向回他们来的地方,如果他们没有登录,则首先呈现登录屏幕(就是这样)。 我同意,绝大多数解释都过于关注在重定向期间发送的消息的细节上。 SSO在概念上非常简单,但我不得不实现一个自制版本才能这么想(并欣赏这些细节;-) - thebjorn
3个回答

61

实现这一目标的方式有很多,并且可能会比较棘手。我可以举一个例子来给你说明:

考虑在不同子域上的两个应用程序:

The Fine Corinthian Turkey Shop (turkey.example.com)
Rent a Baboon (monkey.example.com)

这两个Web应用程序想要共享登录,为其单点登录安排第三个托管网站:

sso.example.com

流程如下:

  1. Frank 访问 http://turkey.example.com/orders/12
  2. Turkey 重定向到 https://sso.example.com/login
  3. SSO 显示用户登录表单,验证并颁发令牌
  4. 令牌被保存在 SSO 的 cookie 中。
  5. 现在用户已经在 SSO 上通过验证,但需要将令牌返回给 turkey。
  6. SSO 在服务器上存储一个组合 (Guid, Token, Expiry),其中 Guid 是随机 GUID,Expiry 大约为30秒。
  7. SSO 在 *.example.com 上设置一个安全 cookie,其中包含 Guid
  8. SSO 重定向回 http://turkey.example.com/orders/12
  9. Turkey 现在可以从 cookie 中检索到票据
  10. Turkey 调用 SSO 服务器并交换票据以获取令牌。
  11. Turkey 将令牌保存在浏览器中(通常是cookie)

现在让我们假设 Frank 想要一些美味多汁的狒狒来配那只火鸡:

  1. Frank 访问: http://monkey.example.com/order-in-bulk
  2. Monkey 发现 Frank 没有存储的令牌,重定向到 https://sso.example.com/login
  3. SSO 发现 Frank 已经登录,因为他有一个存储的令牌。
  4. SSO 在服务器上存储一个新的 (Guid, Token, Expiry) 三元组
  5. 其余流程与初始登录完全相同

5
谢谢您提供这个生动的例子,很有帮助。因此,SSO看到Frank已经登录,因为他有一个存储的令牌(baboons中的#3)。这一点让我感到困惑。SSO如何知道Frank已经登录?Monkey不知道来自Turkey的令牌。SSO使用什么来确定来自Monkey的请求是来自Frank? - Tom Schreck
当用户在SSO登录时,刷新/访问令牌将存储在localStorage中。这将在随后的访问SSO时可用。 - Troels Larsen
2
"Frank想要一些美味多汁的狒狒来搭配那只火鸡" - Frank应该记住他只是租用它们 :) - iandayman
2
@TroelsLarsen,虽然这很好地解释了SSO流程,但本地存储甚至会话存储只适用于非敏感信息,而认证令牌则不是。 - Phillip Martin
1
@PhillipMartin:有趣的观点。在编写这个时,我并没有考虑到安全问题。我同意只使用 Http cookie 会更好。我已经进行了编辑以反映这一点。 - Troels Larsen
显示剩余6条评论

4
然而,如果用户直接打开浏览器并进入App B,那么他们的会话如何与现有令牌建立联系呢?
如果答案是后端服务器上有会话状态,那么如何将App A中已登录的用户与App B的新请求匹配呢?
我认为这更多涉及到Cookie和重定向,而不是令牌。令牌是在用户身份验证后生成的。
所以当您通过浏览器访问App B时,App B会将您的用户代理重定向到认证服务器(该服务器可能会将您重定向到SSO站点)。
需要注意的是,SSO登录请求实际上是您的浏览器和SSO服务器之间的HTTP请求。
因此,SSO cookie已经存在-因为早些时候,App A也会将您的用户代理重定向到认证/SSO服务器,在那里进行登录。然后,SSO服务器可以在您与其之间保持cookie。
我可以看到如果我登录到App A并检索令牌,然后通过将令牌传递给App B从App A启动App B。
不确定我是否理解了App A将其令牌传递给App B的问题。通常应用程序(OAuth 2.0客户端)不会共享令牌。App B应该向认证服务器发出自己的请求,该服务器(如果用户已登录)可以跳过登录部分,但然后需要验证:
1. App B是否具有所请求的范围的权限,以及 2. 登录的用户是否已授予对这些范围的访问权限。
如果用户已登录并且先前已批准了范围访问权限,则所有这些处理对最终用户来说都是无缝的,除了一堆重定向。
这假设您使用隐式授权流(我注意到您的应用程序之一是angularjs应用程序)。
如果您使用代码,密码或客户端凭据Oauth2.0授权,则可能会在用户首次登录和同意后收到刷新令牌。
刷新令牌相当于长期访问(仅针对该应用程序),而无需再次进行登录和获得用户的同意。

0

sso.example.com 存储了一个 cookie,这个 cookie 在 Frank 访问 monkey.example.com 时有帮助。如果 sso.example.com 觉得 cookie 过期,那么它可以要求重新登录 auth


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