Electron应用使用IndexedDB实现登录时出现Invalid security origin错误
Electron登录页面IndexedDB验证问题修复
问题描述
我正在为Electron Web应用开发登录/注册页面,仅使用JavaScript、HTML和CSS,通过IndexedDB存储用户凭证。在Electron窗口的开发者工具Application面板中可确认用户名和密码已成功保存,但用户尝试登录时出现以下错误:Request CacheStorage.requestCacheNames failed. {"code":-32602,"message":"Invalid security origin"}
同时用户会被重定向到空白页面,添加的console.log语句也没有任何输出,尝试添加console.log和alert打印登录信息也无效。
错误根源分析
- 登录表单未绑定提交事件:点击登录按钮后,表单默认执行提交动作,页面直接跳转,导致验证逻辑根本没机会执行。
- 登录验证函数存在多处错误:
- 函数名
e与事件对象重名,导致逻辑混乱 - 未定义
key变量就直接用于索引查询 - IndexedDB的
users对象库未创建email索引,却直接调用store.index('email') window.location.replace(homepage.html)语法错误,目标路径未加引号
- 函数名
- Electron本地文件协议限制:使用
file://协议加载页面时,浏览器安全策略会限制CacheStorage访问,触发Invalid security origin错误。
修复步骤
- 为登录表单添加submit事件监听器,阻止默认跳转行为
- 重构登录验证函数,修正命名、索引创建、变量定义和语法问题
- 在Electron主进程中配置
webPreferences,允许file协议的跨域和存储访问
修正后的代码
JavaScript代码
const signUpBtnLink = document.querySelector('.signUpBtn-link'); const signInBtnLink = document.querySelector('.signInBtn-link'); const wrapper = document.querySelector('.wrapper'); signUpBtnLink.addEventListener('click', () => { wrapper.classList.toggle('active'); }); signInBtnLink.addEventListener('click', () => { wrapper.classList.toggle('active'); }); let $ = document const registerForm = $.querySelector(".form-wrapper-sign-up") const loginForm = $.querySelector(".form-wrapper-sign-in form") const nameInput = $.querySelector("#username") const loginNameInput = $.querySelector("#username1") const loginPasswordInput = $.querySelector("#password1") const passwordInput = $.querySelector("#password") const emailInput = $.querySelector("#email") const table = $.querySelector("table") let db = null let objectStore = null window.addEventListener("load", () => { let DBOpenRequest = indexedDB.open('DreamDB', 2) DBOpenRequest.addEventListener("error", err => { console.warn("DB Error: ", err) }) DBOpenRequest.addEventListener("success", e => { db = e.target.result console.log("DB Success: ", e.target.result) }) DBOpenRequest.addEventListener("upgradeneeded", e => { db = e.target.result console.log("DB Old Version: ", e.oldVersion) console.log("DB Upgraded: ", e) console.log("DB New Version: ", e.newVersion) let userStore; if(!db.objectStoreNames.contains("users")){ userStore = db.createObjectStore('users', { keyPath: "userId" }) } else { userStore = e.target.transaction.objectStore("users") } if (!userStore.indexNames.contains('email')) { userStore.createIndex('email', 'email', { unique: true }); } if(db.objectStoreNames.contains("products")){ db.deleteObjectStore('products') } console.log(db.objectStoreNames) }) }) registerForm.addEventListener("submit", e => { e.preventDefault() let newUserObj = { userId: Math.floor(Math.random() * 9999), name: nameInput.value, password: passwordInput.value, email: emailInput.value } let tx = createTransaction("users", "readwrite") tx.addEventListener("complete", e => { console.log("Write TX Complete: ", e) }) let store = tx.objectStore("users") let req = store.add(newUserObj) req.addEventListener("error", err => { console.warn("Write REQ Error: ", err) }) req.addEventListener("success", e => { console.log("Write REQ Success: ", e) clearInput() }) }) loginForm.addEventListener("submit", (e) => { e.preventDefault() const email = loginNameInput.value; const password = loginPasswordInput.value; if (!db) { alert("数据库未初始化,请刷新页面重试"); return; } const tx = db.transaction(["users"], "readonly"); const store = tx.objectStore("users"); const emailIndex = store.index('email'); const query = emailIndex.get(email); query.onsuccess = function() { if (query.result) { if (password === query.result.password) { console.log('登录成功'); alert(`欢迎登录,${query.result.name}`); window.location.replace('homepage.html'); } else { alert("密码错误,请重新输入"); } } else { alert("该邮箱未注册,请先注册"); } }; query.onerror = function(err) { console.warn("登录查询错误: ", err); alert("登录失败,请稍后重试"); }; }) function getUser() { let tx = createTransaction("users", "readonly") tx.addEventListener("complete", e => { console.log("Get TX Complete: ", e) }) let store = tx.objectStore("users") let req = store.getAll() req.addEventListener("error", err => { console.warn("Get REQ Error: ", err) }) req.addEventListener("success", e => { console.log("Get REQ Success: ", e.target.result) }) } function deleteUser(userId) { let tx = createTransaction("users", "readwrite") tx.addEventListener("complete", e => { console.log("Delete TX Complete: ", e) }) let store = tx.objectStore("users") let req = store.delete(userId) req.addEventListener("error", err => { console.warn("Delete REQ Error: ", err) }) req.addEventListener("success", e => { console.log("Delete REQ Success: ", e) getUser() }) } function createTransaction(storeName, mode) { let tx = db.transaction(storeName, mode) tx.addEventListener("error", err => { console.warn("TX Error: ", err) }) return tx } function clearInput() { nameInput.value = '' passwordInput.value = '' emailInput.value = '' }
HTML代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Dream Mirror | Login</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"> <link rel="stylesheet" type="text/css" href="login.css"> </head> <body> <h1><center>DREAM MIRROR</center> </h1> <div class="wrapper"> <div class="form-wrapper sign-in"> <form> <h2>Sign In</h2> <div class="input-group"> <input id ="username1" type="text" placeholder="输入邮箱" required> <label for="">邮箱</label> </div> <div class="input-group"> <input id = "password1" type="password" placeholder="输入密码" required> <label for="">Password</label> </div> <div class="remember"> <label><input type="checkbox"> Remember me</label> </div> <button> Sign In</button> <div class="signUp-link"> <p>Don't have an account? <a href="#" class="signUpBtn-link">Sign Up</a></p> </div> <div class="social-platform"> <div class="social-icons"></div> </div> </form> </div> <div class="form-wrapper sign-up"> <form class="form-wrapper-sign-up"> <div id ="names"></div> <h2>Sign Up</h2> <div class="input-group"> <input id="username" type="text" placeholder="输入用户名" required> <label for="">Username</label> </div> <div class="input-group"> <input id="email" type="email" placeholder="输入邮箱" required> <label for="">Email</label> </div> <div class="input-group"> <input id="password" type="password" placeholder="输入密码" required> <label for="">Password</label> </div> <div class="remember"> <label><input type="checkbox"> I agree to the terms & conditions</label> </div> <button class="submit">Sign Up</button> <div class="signUp-link"> <p>Already have an account? <a href="#" class="signInBtn-link">Sign In</a></p> </div> </form> </div> </div> <script defer src="login.js"></script> </body> </html>
CSS代码
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;400;700&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'poppins', sans-serif; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: #808080; font-family: 'Poppins', sans-serif; } .wrapper { position: relative; width: 400px; height: 500px; background: rgba(255, 255, 255, .2); border-radius: 20px; box-shadow: 0 0 50px #fff; padding: 40px; } .form-wrapper { display: flex; align-items: center; width: 100%; height: 100%; transition: 1s ease-in-out; } .wrapper.active .form-wrapper.sign-in { transform: scale(0) translate(-300px, 500px); } .wrapper .form-wrapper.sign-up { position: absolute; top: 0; transform: scale(0) translate(200px, -500px); } .wrapper.active .form-wrapper.sign-up { transform: scale(1) translate(0, 0); } h2 { font-size: 30px; color: #fff; text-align: center; font-family: 'poppins' ,sans-serif; } .input-group { position: relative; margin: 30px 0; border-bottom: 2px solid #fff; } .input-group label { position: absolute; top: 50%; left: 5px; transform: translateY(-50%); font-size: 16px; color: #fff; pointer-events: none; transition: .5s; font-family: 'Poppins', sans-serif; } .input-group input { width: 320px; height: 40px; font-size: 16px; color: #fff; padding: 0 5px; background: transparent; border: none; outline: none; font-family: 'Poppins', sans-serif; } .input-group input:focus~label, .input-group input:valid~label { top: -5px; } .remember { margin: -5px 0 15px 5px; } .remember label { color: #fff; font-size: 14px; } .remember label input { accent-color: #f4157e; } button { position: relative; width: 100%; height: 40px; background: #fff; font-size: 16px; color: #f4157e; cursor: pointer; border-radius: 30px; border: none; outline: none; } .signUp-link { font-size: 14px; text-align: center; margin: 15px 0; } .signUp-link p { color: #fff; } .signUp-link p a { color: #f4157e; text-decoration: none; font-weight: 500; } .signUp-link p a:hover { text-decoration: underline; } .social-platform { font-size: 14px; color: #fff; text-align: center; } .social-icons a { display: inline-block; width: 35px; height: 35px; background: transparent; border: 1px solid #fff; border-radius: 50%; text-align: center; line-height: 35px; margin: 15px 6px 0; transition: .3s; } .social-icons a:hover { background: #fff; } .social-icons a i { color: #fff; font-size: 14px; transition: .3s; } .social-icons a:hover i { color: rgba(0, 0, 0, .3); } h1{ text-align: center; font-size: 45px; font-weight: 50; font-family: 'Poppins', sans-serif; position: absolute; top: 20px; left: 50%; transform: translateX(-50%); color: white; } table { font-family: arial, sans-serif; border-collapse: collapse; width: 100%; margin-bottom: 50px; } td, th { border: 1px solid #dddddd; text-align: left; padding: 8px; } tr:nth-child(even) { background-color: #dddddd; } .text-center { text-align: center; }
Electron主进程配置(解决安全origin错误)
const { app, BrowserWindow } = require('electron'); function createWindow() { const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, contextIsolation: false, allowRunningInsecureContent: true, webSecurity: false } }); mainWindow.loadFile('index.html'); mainWindow.webContents.openDevTools(); } app.whenReady().then(() => { createWindow(); app.on('activate', function () { if (BrowserWindow.getAllWindows().length === 0) createWindow(); }); }); app.on('window-all-closed', function () { if (process.platform !== 'darwin') app.quit(); });
内容的提问来源于stack exchange,提问作者Sabrina D
相关产品推荐
相关产品推荐

