一、需求说明
主要用于加载自己的其他项目页面时用iframe和webview等方法无法操作cookie和localstorage等页面缓存,因此用electron来显示并且实现免密登录,主要是免密登录在不同场景下需要用不同的方法来实现。
注意:切记在未获取第三方网站前将别人的网站抓过来显示,容易引发不必要的问题。
二、实现方法
1. 可以通过设置登录令牌的页面
(1)后台通过请求后台接口或者其他方法获取到对应网站的令牌(能调接口的话尽量不要用selenium的方式,非常不稳定)
(2)electron实现免密登录(重点来了)
a.通过cookie保存令牌的情况
function addCookies(cookies){
let setCookies=mainWindow.webContents.session.cookies;
setCookies.set(cookie).then(()=>{
//dosomething
console.log('设置成功');
},(error)=>{
//dosomething
console.error(error);
})
}
需要注意的地方:
1.传入的cookie在构建时要把url和domain都设置上
2.要在主进程访问链接前就添加cookie,也就是mainWindow.loadURL(‘url’)前,不然会导致添加cookie失败
3.最好在添加cookie后稍等2-3秒,可以用setTimeout方法添加个计时器
b.网站是通过localStorage保存令牌
这种只能通过注入js的方法来添加,代码如下
mainWindow.webContents.executeJavaScript(
`localStorage.setItem('` + key + `','` + value + `');`
+`window.location.href = 'yourUrl';`).then((result) => {
//dosomething
});
需要注意的地方:
1. 由于主进程不能直接获取到localStorage,因此只能通过注入js的方法来设置值,
2. 设置完后如果通过mainWindow.loadURL()方法来访问会导致网页读取localStorage失败,具体原因未知,但是可以通过注入js的方法来让网页重新跳转一次来实现。
2. 不能通过设置登录令牌的页面
这种情况只能通过注入js的方法来实现免密登录,具体思路为通过javascript来获取到页面里的登录信息的输入框dom,模拟用户点击登录的方式来实现。
具体注意的问题:
(1)需要等待网页完全加载完后再进行js注入方法
(2)有些网站会进行多次重定向导致无法确定是否进入到了登录页面
(3)由于需求要求不显示登录页面,所以需要在打开页面前添加一个等待加载页面,并且登录后的标题也要进行修改,因此要添加许多的定时器,所以在登录成功后要清除这些定时器
(4)仅限于不需要验证码的页面,如果需要验证码的则需要进行查看页面验证码的加载方法(是前端根据后端返回的字符串还是直接返回的图片流),可以通过接入图片识别或者直接计算验证码的值,过于复杂的验证码考虑检查登录令牌的保存位置来实现。
(5) 由于部分网页含有表单校验,所以需要在每个dom赋值后执行
document.getElementsByClassName('el-input__inner')[1].dispatchEvent(new Event('input', { bubbles: true }));
代码如下:
let winFlag = 0;
createWindow(){
mainWindow = new BrowserWindow({
show: false,
title: baseData.title,
// width: 800,
// height: 600,
webContents: {
openDevTools: true //不想要控制台直接把这段删除
},
resizable: true, // 窗口是否可以改变尺寸 开启后maximizable失效
movable: true, // 窗口是否可以移动
webPreferences: {
preload: path.join(__dirname, 'main-process/preload.js'), //预加载脚本
nodeIntegration: true, // 设置开启nodejs环境
enableRemoteModule: true,// enableRemoteModule保证renderer.js可以可以正常require('electron').remote,此选项默认关闭
contextIsolation: true, //隔离开主进程和渲染进程
},
});
}
mainWindow.loadURL('yourUrl'); // 加载指定第三方网址
mainWindow.webContents.on('did-finish-load', () => {
winFlag++;
var jsFlag = true;
console.log(winFlag);
if (winFlag === 1) {
for (let i = 0; i < 10; i++) {
(function (j) {
let timeId = setTimeout(function timer() {mainWindow.webContents.executeJavaScript(`document.getElementsByClassName('el-input__inner')[1].value='` + username + `';`)
.then((res) => {
mainWindow.webContents.executeJavaScript(`document.getElementsByClassName('el-input__inner')[1].dispatchEvent(new Event('input', { bubbles: true }));`)
mainWindow.webContents.executeJavaScript(`document.getElementsByClassName('el-input__inner')[2].value='` + baseData.password + `';`);
mainWindow.webContents.executeJavaScript(`document.getElementsByClassName('el-input__inner')[2].dispatchEvent(new Event('input', { bubbles: true }));`)
mainWindow.webContents.executeJavaScript(`document.getElementsByClassName('el-form-item__content')[2].getElementsByTagName('button')[0].click();`)
jsFlag = false;
}).catch((error) => {
console.error(">>>" + error + "<<<")
});
//如果执行js成功 则清除全部的定时器
if (!jsFlag) {
winFlag++;
list.forEach((id) => {
clearTimeout(id);
});
}
if (winFlag === 2) {
setTimeout(() => {
destoryLoading()
}, 1000)
}
}, 1000 * i);
list.push(timeId)
})(i);
}
}
});
3.最后附加依赖配置
“devDependencies”: {
“@electron-forge/cli”: “^7.4.0”,
“@electron-forge/maker-deb”: “^7.4.0”,
“@electron-forge/maker-rpm”: “^7.4.0”,
“@electron-forge/maker-squirrel”: “^7.4.0”,
“@electron-forge/maker-zip”: “^7.4.0”,
“@electron-forge/plugin-auto-unpack-natives”: “^7.4.0”,
“@electron-forge/plugin-fuses”: “^7.4.0”,
“@electron/fuses”: “^1.8.0”,
“electron”: “^30.0.1”
},