最近在研究SSO,看到各种复杂的解决方案觉得很疑惑,自己想出了个简单有效的方案,大家来评评有什么问题吗?
服务器A:网站A
服务器B:网站B
服务器C:验证网站(验证表中有UID和KEY两个字段)。
1. 用户打开网站A的页面http://服务器A/a.aspx,检测发现网站Session中没有存储用户名UID。
2. 系统转到验证服务器登录页面,并在QUERYSTRING中附加前一个页面的URL地址。比如http://服务器C/login.asp?URL=http://服务器A/a.aspx
3. 在验证服务器登录成功后更新验证服务器的Session(超时设置为足够长,比如1天)。然后生成一个GUID值,写入验证表。最后,把这个GUID值和UID保存到一个类中序列化后附加在URL中返回网站A的那个页面。比如http://服务器A/a.aspx? token=sadhsagdkjasgyugd7d8yweihasdiuhagsdiuashdhaiushdi
4. 网站A的页面读取QUERYSTRING,然后反序列化出一个类,读取类的UID和KEY信息。然后,从数据库中查找匹配的记录,如果找到了则表明登录成功,并把这条记录的KEY更新成另外一个GUID(这样就保证了即使这个URL被别人拿走再登录都不能成功)。把UID写入服务器A的Session中即可。
5. 用户打开网站B的页面http://服务器B/b.aspx,服务器B上没有当前用户的Session信息,自动转向验证服务器检测是否存在Session,如果找到了表明用户已经登录过,再重复步骤3和4,如果没有找到就转到验证服务器的登录页面。
巧妙之处在于:
l 网站服务器和验证服务器都拥有一份和用户关联的Session,验证到时候不需要传任何和UID相关的信息,因此也可以跨服务器。正因为如此不需要使用cookie也解决了跨域名。
l 网站服务器和验证服务器可以使用自己的状态机制(不一定是Session),因此跨平台也没有问题。
l 用于验证用户的TOKEN使用GUID在每次验证的时候都会更换,而且GUID和UID是捆绑在一起的,即使GUID碰巧对上了也不知道这个GUID对应了哪个UID。
l 通过验证服务器的验证后,服务器发回的token数据经过了序列化,用户很难伪造。
(实在不放心还可以对这个token进行加密)
不知道大家是否理解了?
更新:经过网友提醒,我想到这个方案在登出的时候有严重问题,比如A网站登出了,我们不能通知其它网站该用户已经登出,它再切换到其它网站又是登录状态(因为Session没有过期),不过我也想到了一个解决方案。就是所有的网站都有一个专门的页面或者服务,根据传过来的令牌来清空这个当前用户的Session。登出以后把所有网站的Session都清空,如果网站不是很多的情况下还好,网站一多登出就会很慢了!
更新:现在看来已经没有什么问题了,到时候放出完整DEMO!
更新:有网友不理解为什么关闭浏览器所有网站退出登录?因为Session是和用户浏览器实例关联的,而我们所有网站都使用Session,因此关闭了浏览器所有网站都退出了。这个和退出登录按钮不一样,退出登录按钮需要发通知让所有网站清除Session。
更新:我们现在把这个框架的登录放到了各个网站中,保证登录和退出在登录服务器Down的情况下也能进行,只是不能进行跨站登录罢了。登录服务器Down还能实现本站登录和退出。过几天放出完整源代码!