背景
公司来了一个业务,让我们的登录对接对方系统的AD域实现免密登录。目前对方能提供的如下
- 对方是某国企,需要走的流程比较多,所以还没拿到对方提供的demo。
- 经过领导决定暂时先让后端自己实现一套,前端进行模拟。
开发
第一版开发
- 前后端去网上找对应的demo
- 经过技术调研后,后端自己研究部署了一个AD域验证的服务
- 我和后端按照类似下方的OAuth 2.0的流程进行对接,搞定,收工
第二个版本开发(对方提供了对接文档,准备进行对接)
过了几周,我收到了一份对接文档。
对方发了一个AD域的地址,并且有以下的信息
重点有一条信息:前端调用接口页面获取当前电脑域账号和密码
第二个版本开发(梳理思路)
这个跟普通的接口请求不同,是直接返回了个html,前端怎么才能拿到这个页面的信息。
对于这个问题我进行了如下的尝试。
- 认证的页面是对方提供的页面。我不能在他的代码中用postmessage进行通信
- 直接用iframe进行嵌入,读取dom,这个也不行,因为存在跨域的问题。
- 既然都不行,那我用nginx转发,不用浏览器绕过这个跨域的问题,本地可以先用devserver进行测试
第二个版本开发(验证)
- 先在网上随意找个页面,就用了菜鸟课程的页面。
- 本地测试 本地配置了devServer,先获取下菜鸟课程的html的页面,获取到了没问题
- 开发环境验证 在开发环境进行测试,修改了nginx的配置下,接口的返回值中拿到了html的值
- 用对方的demo进行验证 ,但是出问题了,仔细检查了下,当输入完域账号的时候,中间是有一个302的过程,所以我的前端是拿不到html的。
- 修改nginx的配置再次测试,配置了location和reWrite,修改后还是不行。
我已经毫无办法了,当时我在想,这个会不会对方的文档有问题
请求领导再次沟通
毫无办法的我只能让领导去和他们沟通,要到了他们的测试环境
用他们的测试环境进行了测试,调试了他们测试环境的代码,就发现了下方的关键代码。
js
<script>
var ifr = document.createElement("iframe");
ifr.id = "iframeId";
ifr.src = "./test.html";
ifr.style.display = "none";
document.body.appendChild(ifr);
ifr.onload = () => {
ifr.onload = () => {
ifr.contentWindow.close();
};
ifr.contentWindow.location = "about:blank";
};
</script>
看到了一个window.name,什么东西,就去网上搜了搜
这个时候搜集到了阮一峰老师的文章
这个时候大概理解了,为什么对方提供的demo中有一个window.name了,看下方的控制台的截图
把他们的核心代码拷贝过来,就实现跨域也可以拿到数据。
后来跟以前的领导沟通,确实很早之前,确实会用window.name进行跨域,不过现在用的少了。
window.name的学习
概念
在MDN的截图中有如下
通过MDN看这个概念确实很抽象,我们通过例子来看看他的应用场景
例子
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script>
var myWindow;
function openWin() {
myWindow = window.open("", "MsgWindow", "width=200,height=100");
myWindow.document.write("<p>窗口名称为: " + myWindow.name + "</p>");
}
</script>
</head>
<body>
<input type="button" value="打开我的窗口" onclick="openWin()" />
</body>
</html>
运行效果如下
看到这里可能觉得没什么应用场景,那我们再看一个例子
这个是index.html
js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div>我是主页面</div>
<script>
var ifr = document.createElement("iframe");
ifr.id = "iframeId";
ifr.src = "./test.html";
ifr.style.display = "none";
document.body.appendChild(ifr);
ifr.onload = () => {
ifr.onload = () => {
ifr.contentWindow.close();
};
ifr.contentWindow.location = "about:blank";
};
</script>
</body>
</html>
子页面的逻辑很简单,script只有一行,设置window.name的值为du
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>我是被嵌入的iframe</div>
<script>
window.name="du"
</script>
</body>
</html>
运行效果如下 我们可以看到,我们在主页面可以拿到嵌入的iframe的name,这个就代表可以跨域进行通信,可以拿到数据了,上面的跨域拿到用户信息的也就可以解释的通了。
总结
- 当与第三方公司对接的时候,最好是能拿到对方提供的文档后,再进行开工。如果直接开工,会多做很多的无用功
- window.name在某些场景下也可以处理跨域