使用Java在不同域之间实现单点登录[SSO]

25

我们正在实现跨多个应用程序的单点登录[SSO],这些应用程序托管在不同的域和不同的服务器上。

图片描述

现在如图所示,我们引入了一个认证服务器,它实际上与LDAP交互并对用户进行身份验证。将要与认证服务器一起使用/通信的应用程序托管在不同的服务器和域上。

对于SSO,我不能使用会话变量,因为有不同的服务器、不同的应用程序和不同的域,域级别的cookie/会话变量没有帮助。

我正在寻找更好的解决方案,可用于跨它们进行SSO。是否存在任何演示实现?如果是,请发布它或将我指向正确的方向。


1
如何实现Kerberos登录? - John Smith
有许多用于Java的SSO选项。我目前正在使用Fediz实现一个ADFS(Active Directory联合服务)客户端。 - Raystorm
5个回答

43
您可以通过在认证服务器上实现所有登录来实现此目的。其他应用程序可以通过后台通道与认证服务器通信。一般原则如下:
1.用户访问应用程序1。 2.应用程序1需要用户登录,因此它通过后台通道向认证服务器发送令牌。然后,应用程序1将用户重定向到认证服务器上的登录页面,并将令牌作为请求的参数。 3.用户登录到认证服务器。认证服务器设置一个cookie,将令牌标记为已验证并将用户详细信息与之关联。然后认证服务器会将用户重定向回应用程序1。 4.应用程序1收到用户请求并通过后台通道调用认证服务器以检查令牌是否有效。认证服务器以用户详细信息响应。 5.现在应用程序1知道用户已经被授权并拥有一些基本的用户详细信息。
这里是SSO的部分:
6.用户访问应用程序2。 7.应用程序2需要用户登录,因此它通过后台通道向认证服务器发送令牌。然后,应用程序2将用户重定向到认证服务器上的登录页面,并将令牌作为请求的参数。 8.认证服务器看到有一个有效的登录cookie,因此它可以判断用户已经得到了授权,并且知道他们是谁。认证服务器将令牌标记为已验证并将用户详细信息与之关联。然后认证服务器会将用户重定向回应用程序2。 9.应用程序2收到用户请求并通过后台通道调用认证服务器以检查令牌是否有效。认证服务器以用户详细信息响应。 10.现在应用程序2知道用户已经被授权并拥有一些基本的用户详细信息。

有一些现有的实现该方法,例如CAS(中央认证服务)。请注意,Spring Security开箱即用地支持CAS。我建议您考虑使用现有的实现方法,因为自己编写将会很困难。在我的答案中,我已经简化了一些内容,如果您对此不熟悉,可能会引入安全漏洞。


1
看起来我现在理解了流程,看起来不错。正如你提到的安全漏洞,是的,这是我第一次使用SSO,并且我将独自工作。所以,您能否指出是否有人已经开发了适当的安全性,以便我可以遵循类似的设计方法。 - RaceBase
4
@Reddy - 我创建过使用CAS和Spring安全性实现SSO的网站。我从未尝试过自己编写SSO实现,也绝不会尝试。 - Qwerky
1
应用程序2如何获取令牌?分享方法是什么? - Golnaz Saraji

3
我会推荐您查看OAuth。它是一个好的认证和授权协议,被包括Facebook、Google、Windows Live在内的多个大型组织使用。它可能有一个初始学习曲线,但它是一个生产级的解决方案。
它还具有Java、Ruby、PHP等各种编程语言的库。
例如,以下Java服务器端实现可用:
  • Apache Amber(草案22)
  • Spring Security for OAuth
  • Apis Authorization Server(v2-31)
  • Restlet Framework(草案30)
  • Apache CXF
还有以下客户端Java库可用:
  • Apache Amber(草案22)
  • Spring Social
  • Spring Security for OAuth
  • Restlet Framework(草案30)
请参阅以下链接获取更多详细信息:

2
"OAuth 2.0 不是一个身份验证协议。" http://oauth.net/articles/authentication/ - Dherik

1
更大的问题是你如何实现单点登录。许多开源甚至专有(IBM Tivoli)的解决方案都提供跨域单点登录功能。这将是实现跨域SSO的最简单和最好的方法。您可以在所选的SSO服务器中配置使用的LDAP服务器。以OpenSSO为例,以下是一个配置跨域单点登录的文章http://docs.oracle.com/cd/E19681-01/820-5816/aeabl/index.html。要在OpenSSO中配置LDAP,请参考此文档http://docs.oracle.com/cd/E19316-01/820-3886/ghtmw/index.html。有关此问题的参考资料在此处呈现为一个整洁的图表http://docs.oracle.com/cd/E19575-01/820-3746/gipjl/index.html

根据您使用的产品,您可以配置跨域单点登录。

有了这个功能,您的图表将如下所示,其中认证服务器是与您选择的SSO服务器进行交互的实用程序。

拥有与SSO通信的认证服务器是一个合理的架构原则。我建议使用REST终端点进行身份验证调用,这些终端点可以通过HTTP从不同的应用程序进行调用。

Cross Domain single sign on


0

您不能使用Rest服务。

您可以使用我所谓的引荐者URL身份验证。假设您在www.AAAA.com上运行一个身份验证应用程序,在您想要进行身份验证的应用程序中,您可以设置一个过滤器,该过滤器在其域中查找已经通过身份验证的cookie,否则将重定向到www.AAAA.com进行身份验证

成功身份验证后,您可以将用户配置文件信息作为加密的GET / POST数据传递回应用程序


我计划使用REST/WebService。 我的担忧是:
  1. 如何知道用户已经登录?如果我有一个共同的域,可以使用会话变量来维护数据。但是如果我们使用多个域,我如何知道用户是否已经登录。
对于第二种方法,您是否有任何可行的教程来实现这样的过滤器?这就是我所考虑的,但是我不确定是否有过滤器可以做到这一点。
- RaceBase
第一次用户在domain1中打开app1时,它将与Auth服务器联系,该服务器将登录到系统并向app1服务器返回一些消息。现在用户在domain2中打开了app2,现在app2如何检查用户是否已经登录,并且不应显示任何登录表单,因为他已经从app1登录了。 - RaceBase
是的,我明白了。我已经更新了我的答案。我没有过滤器的代码,它只是一个简单的过滤器,会拦截所有请求,检查是否已认证,否则重定向到认证应用程序。 - Sudhakar

-1

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