如何在Electron.js中安全调用SQL查询局域网非本地数据库?
问题描述
我正在开发一个需查询SQL数据库的系统,该数据库位于局域网内但非本地主机(非SQLExpress)。已实现从网页获取用户输入并将信息发送至Main.js,但不确定查询数据库的最优方式。对SQL和Electron.js均不熟悉,遇到以下问题:
- 参考Stack Overflow方案编写的代码中,
dbFunctions不存在get方法,不清楚所需的SQL模块 - 不知道如何根据用户输入的账号密码修改数据库配置
- 硬编码登录逻辑可运行,但数据库查询部分无法正常工作
解决方案
1. 修正依赖与模块选择
你当前引入的sql模块不是正确的SQL Server操作库,代码里已经引入了tedious(SQL Server官方推荐的Node.js操作库),直接基于它实现数据库操作即可,无需额外的sql模块。
先确保安装依赖:
npm install tedious
2. 重构数据库连接与登录验证逻辑
步骤1:修改main.js的核心逻辑
将固定数据库配置改为可动态传入用户凭证的方式,同时实现安全的参数化查询(防止SQL注入):
const { app, BrowserWindow, ipcMain } = require('electron'); const { Connection, Request, TYPES } = require('tedious'); const path = require('path'); let mainWindow; // 数据库基础配置(不含用户凭证) const baseDbConfig = { server: '局域网数据库IP或主机名', // 替换为你的实际地址 authentication: { type: 'default', options: {} // 留空,后续填充用户输入的账号密码 }, options: { encrypt: false, // 局域网环境通常无需加密,按需调整 database: '目标数据库名称', // 替换为你的数据库名 trustServerCertificate: true // 局域网内可开启,避免证书验证问题 } }; function createWindow() { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: false, // 关闭node集成,提升安全性 contextIsolation: true, preload: path.join(__dirname, 'preload.js') }, }); mainWindow.loadFile(path.join(__dirname, 'index.html')); mainWindow.on('closed', () => { mainWindow = null; }); } app.on('ready', () => { createWindow(); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); // 处理登录IPC请求 ipcMain.on('login', (event, loginData) => { const { username, password } = loginData; console.log(`收到登录请求:用户名=${username}`); // 动态生成带用户凭证的数据库配置 const dbConfig = { ...baseDbConfig, authentication: { ...baseDbConfig.authentication, options: { userName: username, password: password } } }; // 创建数据库连接 const connection = new Connection(dbConfig); connection.on('connect', (err) => { if (err) { console.error('数据库连接失败:', err.message); event.reply('login-status', false); return; } // 参数化查询,避免SQL注入 const query = "SELECT COUNT(*) AS count FROM 你的用户表名 WHERE username = @username AND password = @password"; const request = new Request(query, (err) => { if (err) { console.error('查询失败:', err.message); event.reply('login-status', false); } connection.close(); }); // 添加查询参数 request.addParameter('username', TYPES.NVarChar, username); request.addParameter('password', TYPES.NVarChar, password); // 处理查询结果 let loginSuccess = false; request.on('row', (columns) => { columns.forEach(column => { if (column.value > 0) loginSuccess = true; }); }); // 查询完成后返回结果 request.on('requestCompleted', () => { event.reply('login-status', loginSuccess); }); connection.execSql(request); }); // 连接错误处理 connection.on('error', (err) => { console.error('数据库连接错误:', err.message); event.reply('login-status', false); }); });
步骤2:修正preload.js的安全暴露逻辑
Electron中数据库操作必须在主进程完成,渲染进程仅能通过IPC通信调用,简化preload代码:
const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('ElectronAPI', { // 发送登录请求到主进程 login: (credentials) => ipcRenderer.send('login', credentials), // 监听登录状态返回 onLoginStatus: (callback) => ipcRenderer.on('login-status', (_, isSuccess) => callback(isSuccess)) });
步骤3:更新renderer.js的IPC调用
使用preload暴露的安全API,避免直接操作ipcRenderer:
const loginForm = document.getElementById('login-form'); const usernameInput = document.getElementById('username'); const passwordInput = document.getElementById('password'); loginForm.addEventListener('submit', (event) => { event.preventDefault(); const username = usernameInput.value.trim(); const password = passwordInput.value.trim(); if (!username || !password) { alert('请输入用户名和密码'); return; } // 调用preload暴露的API发送登录请求 window.ElectronAPI.login({ username, password }); }); // 监听登录状态结果 window.ElectronAPI.onLoginStatus((isSuccess) => { const messageElement = document.createElement('p'); if (isSuccess) { messageElement.textContent = '登录成功'; messageElement.style.color = 'green'; } else { messageElement.textContent = '用户名或密码错误'; messageElement.style.color = 'red'; } loginForm.appendChild(messageElement); setTimeout(() => { loginForm.removeChild(messageElement); }, 2000); });
3. 关键注意事项
- 安全规范:永远不要在渲染进程直接操作数据库,必须通过主进程IPC通信完成;强制使用参数化查询,杜绝SQL注入风险。
- 局域网配置:确保Electron所在设备能访问局域网数据库服务器,检查防火墙、数据库端口(默认1433)是否开放。
- 密码存储:生产环境中禁止明文存储密码,建议数据库存储密码哈希值(如SHA256),登录时对比哈希值而非明文。
内容的提问来源于stack exchange,提问作者addyHyena
相关产品推荐
相关产品推荐

