1 作者:kongqz
1.1 blog:http://blog.youkuaiyun.com/kongqz
2 目标
2.1 对于同一域下的所有网站只需登录一次
举例来说:
www.baidu.com
aaa.baidu.com
bbb.baidu.com
我只需要在一个地方登陆,访问他的任何一个子系统都不需要登陆
2.2 服务器端的session能经得起大量的用户登录数据存储
传统的互联网方式是通过session复制或者将session会话保持到指定的子节点。但是缺陷是,session数据量越大访问性能越堪忧。
通过ip或者cookie路由的方式很容易造成节点访问不均匀
2.3 浏览器关闭session失效
这个是保证访问安全,大部分电商网站都这么做
2.4 数据的读取不能给数据库较大的压力
我们不能将这些访问频度较高的数据存储到数据库,这样会将数据库压垮
2.5 多节点访问的时候session不失效
可以通过ip路由或者会话复制绑定的方式处理。但是很容易负载不均匀
3 前提知识
3.1 cookie的生命周期
当我们不设置cookie的生命周期的时候,cookie的相关数据存储在内存中。随着浏览器的关闭而失效。
这里需要注意的是,现在的浏览器支持多个tag的方式,如果只是关闭tag,并不意味着当前访问的系统的cookie已经销毁。只有当前浏览器关闭才能进行cookie的销毁。
3.2 sessionid的生成机制
在tomcat中,不论是在windows还是linux下。sessionid是应用服务器取得的随机数进行md5加密后生成了。针对每个浏览器客户端分配一个sessionid,作为交互凭据。
sessionid以cookie形式存储在客户端,其他设置到session中的数据存储在服务器端。
3.3 memcache的存储机制
memcache是一个分布式cache server。当超过生存周期的时候自动失效。
memcache是一个key-value形式的cache server
4 实施方案
4.1 核心思路
4.1.1 获取应用服务器为访问的浏览器生成的sessionid
这个在java中只能通过request.getSessionid()方式获取
4.1.2 将获取的sessionid存储到cookie中
这样任何一个子域名下的系统都可以在浏览器不关闭的情况下按照 sessionid(每个客户端不同)+sessionKeyname获取到cache server中存储的session值。
4.1.3 仿照httpsession将服务器端的session数据都存储到memcache中
主要就是以刚才存储的sessionid作为变量将数据进行存储
4.2 架构缺点
4.2.1 如果所有的程序访问都需要判定session是否存在,cache的访问频次过高
如果我们需要对每个请求都进行用户基本信息的调取,那么cache server的访问频次基本上等同于PV
相对于传统将session存储在单个节点的sever端。session是可以通过路由层的ip hash或者F5的session保持的方式只存储在访问节点的本地
4.2.2 当用户不注销退出系统,存储压力较大
一般我们存储到memcache中的数据失效时间都是1天
5 拓展
主要是针对sso的一些具体应用的扩展。看我们如果尽可能少的做代码修改完成单点登录
5.1 子系统设计
这个是开放平台的核心设计思路
这里和下边谈到的系统互信设计最大的区别就是子系统可以在较长的一段时间内使用相同的参数反复校验访问权限。
5.1.1 SSO主系统端提供sessionid和sessionkey
例如我们登陆腾讯的Qzone,访问他应用中心中的应用,这个时候我们传送刚才登陆时候的sessionid和sessionkey(可以是用户的id号进行hash处理后的字符串)等信息给应用。
5.1.2 服务器端提供验证当前用户是否登陆的接口
SSO提供一个授权的应用可以访问的验证某个用户是否登陆的service接口
5.1.3 子系统根据传送过来的sessionkey和sessionid配合与sso系统的约定密钥进行登陆验证
一般是子系统的id号和密钥以及传送过来的sessionid和session可以这些信息反过来请求sso主系统看当前登陆的用户是不是已经登陆主系统了。
5.1.4 子系统建立自己的session验证机制
子系统如果验证当前用户已经登陆,可以将用户信息存储到本地session中,减少和主系统的交互
5.2 系统互信设计
这个是常见的安全性较高的系统互信场景设计。提出一个一次性票据的概念。保证每次访问的安全性。
场景:
1、主系统登录后访问子系统
2、子系统根据主系统提供的票据以及约定的相关数据项调用主系统确认当期访问用户的权限
3、主系统提供反馈
4、子系统根据反馈进行后续的业务处理
5.2.1 主系统和子系统约定访问密钥
一般主系统会和子系统会约定访问密钥以及系统标识:
1、子系统标识
2、子系统密钥
5.2.2 登录主系统并记录登录状态
一般来说都会将用户的sessionid和用户进行登录绑定。
5.2.3 用户点击子系统并记录访问行为
1、这个动作就是从主系统点连接到子系统的时候记录当前用户的访问记录。
2、生成访问的票据数据,供子系统进行调用验证。
3、如果互信做的严密,票据可以设置成一次性。当子系统校验一次后,直接销毁
备注:
1、这里的票据可以是随机生成的一个字符串
2、一次性的票据为了安全性,票据设置有效期,超过一定期限的票据,定时删除。
5.2.4 子系统根据主系统提供的票据反向访问主系统校验
1、子系统将自己的系统标识、系统密钥、一次性票据作为参数访问主系统进行校验
5.2.5 子系统根据反馈信息进行后续业务处理
如果验证通过,子系统一般都是初始化自己的session,并作session回话保持,这样不需要每次都访问主系统了。
5.3 session集群设计
这个是多节点集群的无侵入解决方案
5.3.1 将session进行集群复制
这个tomcat服务器本身就支持。只需要配置即可。
优点
和程序无关,全部依赖应用服务器的通信
缺点
节点十个以上的时候,性能下降很厉害
5.3.2 重写tomcat的session存储,将session存储到cache服务器中
核心还是在于tomcat的session存储机制。我们需要在特定的定时存储时间点做好数据的更新。尤其是session创建和将近失效的时间点。
详情才可以参考开源项目MSM(memcache Session manager)
5.4 提升活跃用户的登录速度
场景:针对每天都登录的客户的登录访问我们可以适当的提速。因为成熟网站的访问登录都有一个高峰时间点。
5.4.1 计算出站点活跃用户
此处可以根据用户的登录行为进行筛选计算。例如最近一周登录5次的。
5.4.2 每天凌晨开始将活跃用户的用户名密码cache到cache集群
相对于直接查询库进行校验来说,直接访问内存进行校验速度还是有很大提升的。
5.4.3 高峰时间段用户登录的时候直接访问cache集群进行安全性校验
这个策略的缺点就是高峰时间段的新用户或者非活跃用户访问cache损耗了性能。
5.4.4 总结
1、这个策略是针对一些成熟的网站,有忠实的活跃用户比较合适,对于那些用户行为分散的网站,不适合做这个策略。
2、如果网站的访问量较大,并且访问时间比较均匀。可以考虑将登录安全校验机制化,扩大到更广的时间范围。
5.5 用户登录记录存储
我们需要针对用户的登录行为做记录。这里我们直接入库性能损耗较大,一般可以通过如下的思路进行数据存储。
5.5.1 消息服务器异步存储
直接发送到消息服务器中,实时的减轻系统的写入压力。
这里可以考虑采用activemq做集群写入收集。
5.5.2 文件系统存储
存储到本地文件系统,通过日志采集的方式将数据汇总到指定的服务器进行存储。
这里可以考虑下用淘宝的timetunel项目来进行日志收集采集。
BTW:附上mindjet图片,帮助大家理清思路