单点登录研究一

0x00什么是单点登录
在一个服务登录,同时登录其他服务。
PS:代码框架为spring MVC和jquery。

0x01技术难点

  • 跨域访问

  • session同步

0x02什么是跨域访问
在客户端A,访问服务器B,在B的页面1上访问服务器C,页面1跨域访问了服务器C。

0x03为什么要同步session
session是浏览器和服务器的一次回话,如果session不过期,服务器不删除session,之后对该服务器的所有的请求都是同一个session。
单点登录成功之前有两个session有登录状态,一个是A对B的session,B对C的session,A想要登录服务器C,必须把A登录B的session数据同步到A到C的session。

0x04跨域代码
在服务器B的页面post数据到服务器C,在服务器C的controller响应post,前端登录代码如下:

$.ajax({url:uri,timeout:1000,type:'post',data:{
userName : $("#userName").val(),
password : $("#password").val(),
langCode : "zh-cn",
originIp : document.location.origin
 },success:function(result) {
result = JSON.parse(result);
if(result.success&&result.attributes.sessionId){
sucess(result.success, page + "&sessionId="
+ result.attributes.sessionId);
}else{
sucess(false);
}
}}

访问失败,通过chrome控制台网络分析请求,发现是服务器没有开启跨域,

Google之,在controller里配置以下代码允许跨域。

res.setHeader("Access-Control-Allow-Origin", 'IP/*');
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
res.setHeader("Access-Control-Allow-Methods", "POST");
res.setHeader("Allow", "POST");
res.setHeader("P3P", "CP=CAO PSA OUR");

再次访问,可以返回正确的值,成功登录服务器C,把本页面跳转到服务器C的项目主页,发现并没有什么卵用,还是需要登录,服务器C获取的session的用户为空。

0x05session同步
首先在服务器C记录B登录服务器的session信息,在异步方法返回令牌,在响应方法里加入如下代码:

private static Map map = new ConcurrentHashMap();
map.put(session.getId(), session);
AjaxJson j = new AjaxJson();
j.getAttributes().put("sessionId", session.getId());
return j;

在项目的首页加入如下代码,把之前的B的session数据同步给A的session:

String sessionId = request.getParameter("sessionId");
if (StringUtils.isNotBlank(sessionId) && map.containsKey(sessionId)) {
HttpSession session = map.get(sessionId);
HttpSession current = request.getSession();
ClientManager cm = ClientManager.getInstance();
cm.addClinet(current.getId(), cm.getClient(sessionId));
map.remove(sessionId);
current.setAttribute("lang", session.getAttribute("lang"));
session.setMaxInactiveInterval(1);
}

至此完美解决单点登录问题,本机测试毫无压力,客户端A和服务器C均为本机,分为三台也测试通过,当我把服务器B和C放在一台时出现bug,只有第一次访问时可以访问,不管点什么都会要求登录,session又丢了。

0x06debug
分析session之后发现,session超时了。。。。。。。。
当我把服务器B和C放在一台服务器之后,并没有跨域,我在controller里写了session.setMaxInactiveInterval(1);把session超时了。。。。
解决方法一:判断服务和单点服务是否同一个IP,同一个IP就跳过;
解决方法二:session超时时间设置为10分钟;
其他的跨域方式,有时间再写吧。。。
安利两个java类:
java.util.concurrent.TimeUnit,在读这个类之前,完全不知道java的枚举还可以这样玩,[目瞪口呆]表情;
java.net.InetAddress,获取本机IP,request.getLocalAddr()只能得到127.0.0.1。


你可能感兴趣的:(springMVC,跨域访问,单点登录,session同步)