SSO 单点登录例子
?????? 最近想了解下单点登录,网上找了一圈,以下一篇文章介绍的着实令我醍醐灌顶,现转载,为以后使用打下个基础,另:该文章里代码下载路径已经失效,我在CSDN上找了找,确实有,但是我觉得这些发布别人代码的人,既然已经享受到了别人的恩惠,就更该无私的奉献,但却还以10分,5分等的积分让别人下载,真的有点无耻了。
?
代码包:是发布好工程,放在tomcat下即可使用,如有意要学习,可以用反编译工具查看,代码比较简单,容易上手。
?
转载:http://www.blogjava.net/xcp/archive/2010/04/13/318125.html
?
摘要:单点登录(SSO)的技术被越来越广泛地运用到各个领域的软件系统当中。本文从业务的角度分析了单点登录的需求和应用领域;从技术本身的角度分析了单点登录技术的内部机制和实现手段,并且给出Web-SSO和桌面SSO的实现、源代码和详细讲解;还从安全和性能的角度对现有的实现技术进行进一步分析,指出相应的风险和需要改进的方面。本文除了从多个方面和角度给出了对单点登录(SSO)的全面分析,还并且讨论了如何将现有的应用和SSO服务结合起来,能够帮助应用架构师和系统分析人员从本质上认识单点登录,从而更好地设计出符合需要的安全架构。关键字:SSO, Java, J2EE, JAAS1?什么是单点登陆单点登录(Single Sign On),简称为?SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。较大的企业内部,一般都有很多的业务支持系统为其提供相应的管理和IT服 务。例如财务系统为财务人员提供财务的管理、计算和报表服务;人事系统为人事部门提供全公司人员的维护服务;各种业务系统为公司内部不同的业务提供不同的 服务等等。这些系统的目的都是让计算机来进行复杂繁琐的计算工作,来替代人力的手工劳动,提高工作效率和质量。这些不同的系统往往是在不同的时期建设起来 的,运行在不同的平台上;也许是由不同厂商开发,使用了各种不同的技术和标准。如果举例说国内一著名的IT公司(名字隐去),内部共有60多个业务系统,这些系统包括两个不同版本的SAP的ERP系统,12个不同类型和版本的数据库系统,8个不同类型和版本的操作系统,以及使用了3种不同的防火墙技术,还有数十种互相不能兼容的协议和标准,你相信吗?不要怀疑,这种情况其实非常普遍。每一个应用系统在运行了数年以后,都会成为不可替换的企业IT架构的一部分,如下图所示。
随 着企业的发展,业务系统的数量在不断的增加,老的系统却不能轻易的替换,这会带来很多的开销。其一是管理上的开销,需要维护的系统越来越多。很多系统的数 据是相互冗余和重复的,数据的不一致性会给管理工作带来很大的压力。业务和业务之间的相关性也越来越大,例如公司的计费系统和财务系统,财务系统和人事系 统之间都不可避免的有着密切的关系。为了降低管理的消耗,最大限度的重用已有投资的系统,很多企业都在进行着企业应用集成(EAI)。 企业应用集成可以在不同层面上进行:例如在数据存储层面上的“数据大集中”,在传输层面上的“通用数据交换平台”,在应用层面上的“业务流程整合”,和用 户界面上的“通用企业门户”等等。事实上,还用一个层面上的集成变得越来越重要,那就是“身份认证”的整合,也就是“单点登录”。通常来说,每个单独的系统都会有自己的安全体系和身份认证系统。整合以前,进入每个系统都需要进行登录,这样的局面不仅给管理上带来了很大的困难,在安全方面也埋下了重大的隐患。下面是一些著名的调查公司显示的统计数据:
从上面的视图可以看出,要实现SSO,需要以下主要的功能:统一的认证系统是SSO的前提之一。认证系统的主要功能是将用户的登录信息和用户信息库相比较,对用户进行登录认证;认证成功后,认证系统应该生成统一的认证标志(ticket),返还给用户。另外,认证系统还应该对ticket进行效验,判断其有效性。
要实现SSO的功能,让用户只登录一次,就必须让应用系统能够识别已经登录过的用户。应用系统应该能对ticket进行识别和提取,通过与认证系统的通讯,能自动判断当前用户是否登录过,从而完成单点登录的功能。?上面的功能只是一个非常简单的SSO架构,在现实情况下的SSO有着更加复杂的结构。有两点需要指出的是:

3 WEB-SSO的实现随着互联网的高速发展,WEB应用几乎统治了绝大部分的软件应用系统,因此WEB-SSO是SSO应用当中最为流行。WEB-SSO有其自身的特点和优势,实现起来比较简单易用。很多商业软件和开源软件都有对WEB-SSO的实现。其中值得一提的是OpenSSO?(https://opensso.dev.java.net),为用Java实现WEB-SSO提供架构指南和服务指南,为用户自己来实现WEB-SSO提供了理论的依据和实现的方法。为什么说WEB-SSO比较容易实现呢?这是有WEB应用自身的特点决定的。众所周知,Web协议(也就是HTTP)是一个无状态的协议。一个Web应用由很多个Web页面组成,每个页面都有唯一的URL来定义。用户在浏览器的地址栏输入页面的URL,浏览器就会向Web Server去发送请求。如下图,浏览器向Web服务器发送了两个请求,申请了两个页面。这两个页面的请求是分别使用了两个单独的HTTP连接。所谓无状态的协议也就是表现在这里,浏览器和Web服务器会在第一个请求完成以后关闭连接通道,在第二个请求的时候重新建立连接。Web服务器并不区分哪个请求来自哪个客户端,对所有的请求都一视同仁,都是单独的连接。这样的方式大大区别于传统的(Client/Server)C/S结构,在那样的应用中,客户端和服务器端会建立一个长时间的专用的连接通道。正是因为有了无状态的特性,每个连接资源能够很快被其他客户端所重用,一台Web服务器才能够同时服务于成千上万的客户端。
但是我们通常的应用是有状态的。先不用提不同应用之间的SSO,在同一个应用中也需要保存用户的登录身份信息。例如用户在访问页面1的时候进行了登录,但是刚才也提到,客户端的每个请求都是单独的连接,当客户再次访问页面2的时候,如何才能告诉Web服务器,客户刚才已经登录过了呢?浏览器和服务器之间有约定:通过使用cookie技术来维护应用的状态。Cookie是可以被Web服务器设置的字符串,并且可以保存在浏览器中。如下图所示,当浏览器访问了页面1时,web服务器设置了一个cookie,并将这个cookie和页面1一起返回给浏览器,浏览器接到cookie之后,就会保存起来,在它访问页面2的时候会把这个cookie也带上,Web服务器接到请求时也能读出cookie的值,根据cookie值的内容就可以判断和恢复一些用户的信息状态。
Web-SSO完全可以利用Cookie结束来完成用户登录信息的保存,将浏览器中的Cookie和上文中的Ticket结合起来,完成SSO的功能。?为了完成一个简单的SSO的功能,需要两个部分的合作:- 统一的身份认证服务。
- 修改Web应用,使得每个应用都通过这个统一的认证服务来进行身份效验。
<init-param>
<param-name>SSOServiceURL</param-name>
<param-value>http://wangyu.prc.sun.com:8080/SSOAuth/SSOAuth</param-value>
</init-param>
<init-param>
<param-name>SSOLoginPage</param-name>
<param-value>http://wangyu.prc.sun.com:8080/SSOAuth/login.jsp</param-value>
</init-param>
将其中的SSOServiceURL和SSOLoginPage修改成部署SSOAuth应用的机器名、端口号以及根路径(缺省是SSOAuth)以反映实际的部署情况。设置完后,根据你所选择的J2EE容器,可能需要将SSOWebDemo1和SSOWebDemo2这两个目录压缩打包成两个war文件。用“jar -cvf SSOWebDemo1.war SSOWebDemo1/”就可以完成这个功能。


3.2 WEB-SSO代码讲解3.2.1身份认证服务代码解析Web-SSO的源代码可以从网站地址http://gceclub.sun.com.cn/wangyu/web-sso/websso_src.zip下载。身份认证服务是一个标准的web应用,包括一个名为SSOAuth的Servlet,一个login.jsp文件和一个failed.html。身份认证的所有服务几乎都由SSOAuth的Servlet来实现了;login.jsp用来显示登录的页面(如果发现用户还没有登录过);failed.html是用来显示登录失败的信息(如果用户的用户名和密码与信息数据库中的不一样)。SSOAuth的代码如下面的列表显示,结构非常简单,先看看这个Servlet的主体部分:package DesktopSSO;?import java.io.*;import java.net.*;import java.text.*;import java.util.*;import java.util.concurrent.*;?import javax.servlet.*;import javax.servlet.http.*;??public class SSOAuth extends HttpServlet {???????static private ConcurrentMap accounts;????static private ConcurrentMap SSOIDs;????String cookiename="WangYuDesktopSSOID";????String domainname;???????public void init(ServletConfig config) throws ServletException {????????super.init(config);????????domainname= config.getInitParameter("domainname");????????cookiename = config.getInitParameter("cookiename");????????SSOIDs = new ConcurrentHashMap();????????accounts=new ConcurrentHashMap();????????accounts.put("wangyu", "wangyu");????????accounts.put("paul", "paul");????????accounts.put("carol", "carol");????}?????protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {????????PrintWriter out = response.getWriter();????????String action = request.getParameter("action");????????String result="failed";????????if (action==null) {????????????handlerFromLogin(request,response);????????} else if (action.equals("authcookie")){????????????String myCookie = request.getParameter("cookiename");????????????if (myCookie != null)?result = authCookie(myCookie);????????????out.print(result);????????????out.close();????????} else if (action.equals("authuser")) {???????????result=authNameAndPasswd(request,response);????????????out.print(result);????????????out.close();????????}?else if (action.equals("logout")) {????????????String myCookie = request.getParameter("cookiename");????????????logout(myCookie);?? ?????????out.close();????????}????}?.....?}?从代码很容易看出,SSOAuth就是一个简单的Servlet。其中有两个静态成员变量:accounts和SSOIDs,这两个成员变量都使用了JDK1.5中线程安全的MAP类: ConcurrentMap,所以这个样例一定要JDK1.5才能运行。Accounts用来存放用户的用户名和密码,在init()的方法中可以看到我给系统添加了三个合法的用户。在实际应用中,accounts应该是去数据库中或LDAP中获得,为了简单起见,在本样例中我使用了ConcurrentMap在内存中用程序创建了三个用户。而SSOIDs保存了在用户成功的登录后所产生的cookie和用户名的对应关系。它的功能显而易见:当用户成功登录以后,再次访问别的系统,为了鉴别这个用户请求所带的cookie的有效性,需要到SSOIDs中检查这样的映射关系是否存在。?在主要的请求处理方法processRequest()中,可以很清楚的看到SSOAuth的所有功能- 如果用户还没有登录过,是第一次登录本系统,会被跳转到login.jsp页面(在后面会解释如何跳转)。用户在提供了用户名和密码以后,就会用handlerFromLogin()这个方法来验证。
- 如果用户已经登录过本系统,再访问别的应用的时候,是不需要再次登录的。因为浏览器会将第一次登录时产生的cookie和请求一起发送。效验cookie的有效性是SSOAuth的主要功能之一。
- SSOAuth还能直接效验非login.jsp页面过来的用户名和密码的效验请求。这个功能是用于非web应用的SSO,这在后面的桌面SSO中会用到。
- SSOAuth还提供logout服务。
<filter-name>SSOFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>?下面还有几个主要的函数需要说明:????private String SSOService(String cookievalue) throws IOException {????????String authAction = "?action=authcookie&cookiename=";????????HttpClient httpclient = new HttpClient();????????GetMethod httpget = new GetMethod(SSOServiceURL+authAction+cookievalue);????????try {?????????????httpclient.executeMethod(httpget);????????????String result = httpget.getResponseBodyAsString();????????????return result;????????} finally {????????????httpget.releaseConnection();????????}????}???????private void logoutService(String cookievalue) throws IOException {????????String authAction = "?action=logout&cookiename=";????????HttpClient httpclient = new HttpClient();????????GetMethod httpget = new GetMethod(SSOServiceURL+authAction+cookievalue);????????try {????????????httpclient.executeMethod(httpget);????????????httpget.getResponseBodyAsString();????????} finally {????????????httpget.releaseConnection();????????}????}这两个函数主要是利用apache中的httpclient访问SSOAuth提供的认证服务来完成效验cookie和logout的功能。其他的函数都很简单,有很多都是我的IDE(NetBeans)替我自动生成的。4?当前方案的安全局限性当前这个WEB-SSO的方案是一个比较简单的雏形,主要是用来演示SSO的概念和说明SSO技术的实现方式。有很多方面还需要完善,其中安全性是非常重要的一个方面。我们说过,采用SSO技术的主要目的之一就是加强安全性,降低安全风险。因为采用了SSO,在网络上传递密码的次数减少,风险降低是显然的,但是当前的方案却有其他的安全风险。由于cookie是一个用户登录的唯一凭据,对cookie的保护措施是系统安全的重要环节:
在本方案中,cookie是有一个固定的字符串(我的姓名)加上当前的时间戳。这样的cookie很容易被伪造和猜测。怀有恶意的用户如果猜测到合法的cookie就可以被当作已经登录的用户,任意访问权限范围内的资源
在本方案中,虽然密码只要传输一次就够了,可cookie在网络中是经常传来传去。一些网络探测工具(如sniff, snoop,tcpdump等)可以很容易捕获到cookie的数值。在本方案中,并没有考虑cookie在传输时候的保护。另外对cookie的效验也过于简单,并不去检查发送cookie的来源究竟是不是cookie最初的拥有者,也就是说无法区分正常的用户和仿造cookie的用户。
因为有SSO,所以当某个处于?SSO的应用被客攻破,那么很容易攻破其他处于同一个SSO保护的应用。这些安全漏洞在商业的SSO解决方案中都会有所考虑,提供相关的安全措施和保护手段,例如Sun公司的Access Manager,cookie的复杂读和对cookie的保护都做得非常好。另外在OpneSSO?(https://opensso.dev.java.net)的架构指南中也给出了部分安全措施的解决方案。5?当前方案的功能和性能局限性除了安全性,当前方案在功能和性能上都需要很多的改进:
- 运行此桌面SSO需要三个前提条件:
a) WEB-SSO的身份认证应用应该正在运行,因为我们在桌面SSO当中需要用到统一的认证服务
b)?当前桌面需要运行Mozilla或Netscape浏览器,因为我们将ticket保存到mozilla的cookie文件中
c)?必须在JDK1.4以上运行。(WEB-SSO需要JDK1.5以上) - 解开desktopsso.zip文件,里面有两个目录bin和lib。
- bin目录下有一些脚本文件和配置文件,其中config.properties包含了三个需要配置的参数:
a) SSOServiceURL要指向WebSSO部署的身份认证的URL
b) SSOLoginPage要指向WebSSO部署的身份认证的登录页面URL
c) cookiefilepath要指向当前用户的mozilla所存放cookie的文件 - 在bin目录下还有一个login.conf是用来配置JAAS登录模块,本样例提供了两个,读者可以任意选择其中一个(也可以都选),再重新运行程序,查看登录认证的变化
- 在bin下的运行脚本可能需要作相应的修改
a)?如果是在unix下,各个jar文件需要用“:”来隔开,而不是“;”
b) java?运行程序需要放置在当前运行的路径下,否则需要加上java的路径全名。
效验成功以后,便会显示当前登录的用户的基本信息等等。
?这时候再运行第二个桌面Java应用(mailSystem)的时候,就不需要再登录了,直接就显示出来刚才登录的用户。
第三个应用是logout,运行它之后,用户便退出系统。再访问的时候,又需要重新登录了。请读者再制裁执行完logout之后,重新验证一下前两个应用的SSO:先运行第二个应用,再运行第一个,会看到相同的效果。我们的样例并没有在这里停步,事实上,本样例不仅能够和在几个Java应用之间SSO,还能和浏览器进行SSO,也就是将浏览器也当成是桌面的一部分。这对一些行业有着不小的吸引力。这时候再打开Mozilla浏览器,访问以前提到的那两个WEB应用,会发现只要桌面应用如果登录过,Web应用就不用再登录了,而且能显示刚才登录的用户的信息。读者可以在几个桌面和Web应用之间进行登录和logout的试验,看看它们之间的SSO。
6.3桌面样例的源码分析桌面SSO的样例使用了JAAS(要了解JAAS的详细的信息请参考http://java.sun.com/products/jaas)。JAAS是对PAM(Pluggable Authentication Module)的Java实现,来完成?Java应用可插拔的安全认证模块。使用JAAS作为Java应用的安全认证模块有很多好处,最主要的是不需要修改源代码就可以更换认证方式。例如原有的Java应用如果使用JAAS的认证,如果需要应用SSO,只需要修改JAAS的配置文件就行了。现在在流行的J2EE和其他?Java的产品中,用户的身份认证都是通过JAAS来完成的。在样例中,我们就展示了这个功能。请看配置文件login.conf????DesktopSSO {???desktopsso.share.PasswordLoginModule required;???desktopsso.share.DesktopSSOLoginModule required;};当我们注解掉第二个模块的时候,只有第一个模块起作用。在这个模块的作用下,只有test用户(密码是12345)才能登录。当我们注解掉第一个模块的时候,只有第二个模块起作用,桌面SSO才会起作用。?所有的Java桌面样例程序都是标准JAAS应用,熟悉JAAS的程序员会很快了解。JAAS中主要的是登录模块(LoginModule)。下面是SSO登录模块的源码:?public class DesktopSSOLoginModule implements LoginModule {???..........???private String SSOServiceURL = "";???private String SSOLoginPage = "";???private static String cookiefilepath = "";?????.........?在config.properties的文件中,我们配置了它们的值:SSOServiceURL=http://wangyu.prc.sun.com:8080/SSOAuth/SSOAuthSSOLoginPage=http://wangyu.prc.sun.com:8080/SSOAuth/login.jspcookiefilepath=C:\\Documents and Settings\\yw137672\\Application Data\\Mozilla\\Profiles\\default\\hog6z1ji.slt\\cookies.txtSSOServiceURL和SSOLoginPage成员变量指向了在Web-SSO中用过的身份认证模块:SSOAuth,这就说明在桌面系统中我们试图和Web应用共用一个认证服务。而cookiefilepath成员变量则泄露了一个“天机”:我们使用了Mozilla浏览器的cookie文件来保存登录的凭证。换句话说,和Mozilla共用了一个保存登录凭证的机制。之所以用Mozilla是应为它的Cookie文件格式简单,很容易编程访问和修改任意的Cookie值。(我试图解析Internet Explorer的cookie文件但没有成功。)下面是登录模块DesktopSSOLoginModule的主体:login()方法。逻辑也是非常简单:先用Cookie来登陆,如果成功,则直接就进入系统,否则需要用户输入用户名和密码来登录系统。????public boolean login() throws LoginException{????????try {????????????if (Cookielogin()) return true;????????} catch (IOException ex) {????????????ex.printStackTrace();????????}??????if (passwordlogin()) return true;??????throw new FailedLoginException();?}?下面是Cookielogin()方法的实体,它的逻辑是:先从Cookie文件中获得相应的Cookie值,通过身份效验服务效验Cookie的有效性。如果cookie有效就算登录成功;如果不成功或Cookie不存在,用cookie登录就算失败。????public boolean Cookielogin() throws LoginException,IOException {??????String?cookieValue="";??????int cookieIndex =foundCookie();??????if (cookieIndex<0)????????????return false;??????else????????????cookieValue = getCookieValue(cookieIndex);?????username = cookieAuth(cookieValue);?????if (! username.equals("failed")) {?????????loginSuccess =?true;?????????return true;?????}?????return false;?}??用用户名和密码登录的方法要复杂一些,通过Callback的机制和屏幕输入输出进行信息交互,完成用户登录信息的获取;获取信息以后通过userAuth方法来调用远端SSOAuth的服务来判定当前登录的有效性。???public boolean passwordlogin() throws LoginException {????//????// Since we need input from a user, we need a callback handler????if (callbackHandler == null) {???????throw new LoginException("No CallbackHandler defined");????}????Callback[] callbacks = new Callback[2];????callbacks[0] = new NameCallback("Username");????callbacks[1] = new PasswordCallback("Password", false);????//????// Call the callback handler to get the username and password????try {??????callbackHandler.handle(callbacks);??????username = ((NameCallback)callbacks[0]).getName();??????char[] temp = ((PasswordCallback)callbacks[1]).getPassword();??????password = new char[temp.length];??????System.arraycopy(temp, 0, password, 0, temp.length);??????((PasswordCallback)callbacks[1]).clearPassword();????} catch (IOException ioe) {??????throw new LoginException(ioe.toString());????} catch (UnsupportedCallbackException uce) {??????throw new LoginException(uce.toString());????}???????System.out.println();????String authresult ="";????try {????????authresult = userAuth(username, password);????} catch (IOException ex) {????????ex.printStackTrace();????}????if (! authresult.equals("failed")) {????????loginSuccess= true;????????clearPassword();????????try {????????????updateCookie(authresult);????????} catch (IOException ex) {????????????ex.printStackTrace();????????}????????return true;????}???????loginSuccess = false;????username = null;????clearPassword();????System.out.println( "Login: PasswordLoginModule FAIL" );????throw new FailedLoginException();?}??CookieAuth和userAuth方法都是利用apahce的httpclient工具包和远程的SSOAuth进行http连接,获取服务。????????private String cookieAuth(String cookievalue) throws IOException{????????String result = "failed";???????????????HttpClient httpclient = new HttpClient();??????????????GetMethod httpget = new GetMethod(SSOServiceURL+Action1+cookievalue);???????????try {????????????httpclient.executeMethod(httpget);????????????result = httpget.getResponseBodyAsString();????????} finally {????????????httpget.releaseConnection();????????}????????return result;????}?private String userAuth(String username, char[] password) throws IOException{????????String result = "failed";????????String passwd= new String(password);????????HttpClient httpclient = new HttpClient();??????????????GetMethod httpget = new GetMethod(SSOServiceURL+Action2+username+"&password="+passwd);????????passwd = null;???????????try {????????????httpclient.executeMethod(httpget);????????????result = httpget.getResponseBodyAsString();????????} finally {????????????httpget.releaseConnection();????????}????????return result;???????????}?还有一个地方需要补充说明的是,在本样例中,用户名和密码的输入都会在屏幕上显示明文。如果希望用掩码形式来显示密码,以提高安全性,请参考:http://java.sun.com/developer/technicalArticles/Security/pwordmask/7?真正安全的全方位SSO解决方案:Kerberos我们的样例程序(桌面SSO和WEB-SSO)都有一个共性:要想将一个应用集成到我们的SSO解决方案中,或多或少的需要修改应用程序。Web应用需要配置一个我们预制的filter;桌面应用需要加上我们桌面SSO的JAAS模块(至少要修改JAAS的配置文件)。可是有很多程序是没有源代码和无法修改的,例如常用的远程通讯程序telnet和ftp等等一些操作系统自己带的常用的应用程序。这些程序是很难修改加入到我们的SSO的解决方案中。事实上有一种全方位的SSO解决方案能够解决这些问题,这就是Kerberos协议(RFC 1510)。Kerberos是网络安全应用标准(http://web.mit.edu/kerberos/),由MIT学校发明,被主流的操作系统所采用。在采用kerberos的平台中,登录和认证是由操作系统本身来维护,认证的凭证也由操作系统来保存,这样整个桌面都可以处于同一个SSO的系统保护中。操作系统中的各个应用(如ftp,telnet)只需要通过配置就能加入到SSO中。另外使用Kerberos最大的好处在于它的安全性。通过密钥算法的保证和密钥中心的建立,可以做到用户的密码根本不需要在网络中传输,而传输的信息也会十分的安全。目前支持Kerberos的操作系统包括Solaris, windows,Linux等等主流的平台。只不过要搭建一个Kerberos的环境比较复杂,KDC(密钥分发中心)的建立也需要相当的步骤。Kerberos拥有非常成熟的API,包括Java的API。使用Java Generic Security Services(GSS) API并且使用JAAS中对Kerberos的支持(详细信息请参见Sun的Java&Kerberos教程http://java.sun.com/ j2se/1.5.0/docs/guide/security/jgss/tutorials/index.html),要将我们这个样例改造成对Kerberos的支持也是不难的。 值得一提的是在JDK6.0?(http://www.java.net/download/jdk6)当中直接就包含了对GSS的支持,不需要单独下载GSS的包。?8?总结本文的主要目的是阐述SSO的基本原理,并提供了一种实现的方式。通过对源代码的分析来掌握开发SSO服务的技术要点和充分理解SSO的应用范围。但是,本文仅仅说明了身份认证的服务,而另外一个和身份认证密不可分的服务----权限效验,却没有提到。要开发出真正的SSO的产品,在功能上、性能上和安全上都必须有更加完备的考虑。