三无老旧系统单点登录技术

时间:2024-04-11 22:01:54

  关于多系统单点登录,这并非陌生概念。然而在企业应用系统的建设过程中,多个应用系统一般是在不同时期开发完成的,各应用系统由于功能侧重、设计方案和开发技术有所不同,也就形成了各自独立的用户库和用户认证体系。这也是在实施单点登录改造时,面临的最大问题,而其中尤以大量存在的“三无系统”成为单点登录改造实施的最大拦路虎。   

三无老旧系统单点登录技术

    关于单点登录技术,最近在研究,单点登录包含好几个方面,接入前后端分离的单点登录系统,这个相对比较简单些,选择的鉴权验证机制也比较多,因为大多数前后端分离的系统是基于token验证的,不存在跨域问题,但是如果要接入第三方的老系统的话,如果老系统有人在维护,可以改代码的话也比较简单,但是如果是三无老旧系统的话就比较麻烦了。

   所谓“三无系统”是指企业中没有提供单点登录对接接口,没有源码可以修改、过保,没有厂家支撑的存量系统。企业中的“三无系统”使用这种方式进行单点登录集成,在落地上存在较大的难题,首先是实施成本高,需要调动原厂修改程序,费用高;其次是实施复杂,涉及开发者较多,实施周期长;再之扩展性差,跟系统厂家、应用的平台、环境有关,有些系统不能进行单点登录改造。

   那么对于这些三无系统我们是如何处理的呢?为此我也是进行了大量的验证,找解决方案,因为我是做后端开发的,首先想到的是从java后端出发,首先肯定的是模拟登录请求,将模拟登陆请求的sessionid传入到response中,然后通过后端重定向到三无系统登录后的页面,其中需要注意的是cookie设置domain解决跨域问题,按照这个思路我写了如下接口代码。

@GET
@Path("/formLogin")
@ApiOperation(value = "auth模拟登陆")
public void formLogin(@Context HttpServletRequest request, @Context HttpServletResponse response) {
    String CookieValue = "";
    String loginUrl = "http://zsyz.dev.jpsycn.com/admin/check.do";
    String dataUrl = "http://zsyz.dev.jpsycn.com/admin/index.do";
    String userName = request.getParameter("userName");
    String password = request.getParameter("password");
    System.out.println("userName "+userName+" password "+password);
    HttpClient httpClient = new HttpClient();
    httpClient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "utf-8");
    PostMethod postMethod = new PostMethod(loginUrl);
    NameValuePair[] postData = {new NameValuePair("userName", userName),
            new NameValuePair("passWord", password)};
    postMethod.setRequestBody(postData);
    try {
        httpClient.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
        int statusCode=httpClient.executeMethod(postMethod);
        System.out.println("code==============="+statusCode);
        httpClient.executeMethod(postMethod);
        System.out.println("httpclient的cookie "+httpClient.getState().getCookies());
        String JSESSIONID = "";
        org.apache.commons.httpclient.Cookie[] cookies = httpClient.getState().getCookies();
        for (int i = 0; i < cookies.length; i++) {
            CookieValue = CookieValue+cookies[i]+";";
            if(i==0){
                String sp[] = cookies[i].toString().split("=");
                JSESSIONID = sp[1];
            }
        }
        if(statusCode==200) {//重定向到新的URL
            CookieValue+=" Domain=jpsycn.com;";
            System.out.println("模拟登录成功 "+CookieValue);
            GetMethod getMethod = new GetMethod(dataUrl);
            getMethod.setRequestHeader("Cookie", CookieValue);
            postMethod.setRequestHeader("Host", "zsyz.dev.jpsycn.com");
            postMethod.setRequestHeader("Referer", "http://zsyz.dev.jpsycn.com/admin/login.do");
            postMethod.setRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36");
            httpClient.executeMethod(getMethod);
            String result = getMethod.getResponseBodyAsString();
            Cookie cookie = new CookieBuilder()
                    .setName("JSESSIONID")
                    .setValue(JSESSIONID)
                    .setDomain("jpsycn.com")
                    .setPath("/")
                    .setExpireSeconds((int)(60))
                    .build();
            response.addCookie(cookie);
            System.out.println("登陆成功的cookie "+CookieValue+"  header  "+response.getHeader("Set-Cookie"));
            response.sendRedirect("http://zsyz.dev.jpsycn.com/admin/index.do");
        }else{
            System.out.println("登录失败");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

这种思路实现的代码虽然能模拟登录成功,但是因为并不是token验证机制,每次重定向后的页面cookie中的sessionid都会变化,所以这种方案并不可行。

接下来我们来从前端着手看看能不能实现,前端实现的话也分带验证码不带,我们之前看了不少公司的产品,他们有个插件可以获取到form表单登录的用户名,密码,带验证码的他们目前还做不到,但是我做到了,一会分享代码。

先来看看不带验证码的,以http://zsyz.dev.jpsycn.com/admin/login.do郑州市招商引资平台来说。

三无老旧系统单点登录技术

模拟登录了一下获取登录了一下

三无老旧系统单点登录技术

发现他是form表单登录的,这时我们使用网上说的密码代填方式,说白了就是表单登录,还不能是ajaxForm这种形式的表单提交,这样会出现跨域问题,但是这种提交会返回json的验证数据,我们怎么接收呢?我是采用了ifream的形式展示在页面上,当时实际上应该隐藏着的,前端页面我部署在自己的121.36.107.248服务器上,如果直接通过ip访问会出现跨域问题,这时我就会想到配子域名的方式,于是我在host文件中配置了一下,用一个和这个平台二级域名相同的域名映射到我的服务器ip上,实际上这个操作应该nginx来实现,但想到要购买域名,所以就先改host文件。

三无老旧系统单点登录技术

通过http://zsyz2.dev.jpsycn.com/index.html访问我自己的前端页面

三无老旧系统单点登录技术

三无老旧系统单点登录技术

接下来我们来看看有验证码的系统如何模拟登录,我们以http://218.28.223.243:9000/zzjyw/loginController.do?login

三无老旧系统单点登录技术

我们要考虑的问题是验证码和接口调用是在218的域下,前端页面部署在121的域下,就是要处理这俩问题才能解决跨域问题,于是我在host文件下配置了映射。

三无老旧系统单点登录技术

然后验证码也是通过aaa的域名访问,接口也是aaa,前端页面部署在121用bbb访问,这就可以解决跨域问题。

三无老旧系统单点登录技术

三无老旧系统单点登录技术

下边我附上前端的主要代码,想要全部代码或者有什么疑问可以关注公众号“蛋皮皮”进行咨询。

<iframe id="frameFile" name="frameFile" style="display:text"></iframe>
<form action = "http://www.aaa.baixing.com:9000/zzjyw/loginController.do?checkuser" method="post" id="formP" target="frameFile">
<input type="text" id="userName" name="userName" value="admin"/>
<input type="text" id="password" name="password" value="3edc#EDC"/>
<input type="text" id="randCode" name="randCode" />
<input type="text" id="orgId" name="orgId" value=""/>
<input type="langCode" id="langCode" name="langCode" value="zh-cn"/>
<input type="button" id="btn"  value="表单登录" />
<img src="http://www.aaa.baixing.com:9000/zzjyw/randCodeImage"/>
</form>

点击事件

var oForm = document.querySelector('#formP');
 var oBtn = document.querySelector('#btn');
oBtn.onclick = function(){
alert("111");
oForm.submit();
var int=self.setInterval(function(){  // 这个方法是说在延迟两秒后执行大括号里的方法
window.location.href="http://www.aaa.baixing.com:9000/zzjyw/loginController.do?login";
},2000)  //这里2000代表两秒
}

喜欢请关注“蛋皮皮”公众号