已配置登录验证仍可直接访问admin.html等受保护页面的问题求助
解决直接输入URL绕过登录验证的权限问题
问题根源
你的代码里配置了app.use(express.static(__dirname + '/')),这会把项目根目录设为静态资源目录。当用户直接在地址栏输入/admin.html或/client.html时,Express的静态文件中间件会优先匹配并直接返回对应的HTML文件,完全跳过了你后面定义的带权限验证的路由逻辑。这就是直接输入URL能绕过验证的核心原因。
解决方案
1. 调整静态资源目录结构
不要把项目根目录暴露为静态资源目录,仅将需要公开的静态文件(如样式、脚本、图片等)放在单独的子目录(比如public)中:
// 先引入path模块(如果还没引入) const path = require('path'); // 修改静态中间件配置,只暴露指定目录的资源 app.use(express.static("style")); app.use(express.static(path.join(__dirname, 'public')));
将admin.html和client.html保留在项目根目录,不要放到public或style目录下,这样静态中间件无法直接访问它们。
2. 确保路由逻辑正常生效
调整静态中间件后,当用户访问/admin.html或/client.html时,请求会落到你定义的带权限验证的路由上,触发isAuthenticated和角色验证中间件,未登录用户会被重定向到登录页。
3. 增强Cookie安全性(可选但推荐)
为了防止Cookie被窃取或篡改,设置Cookie时添加安全属性:
// 登录时设置Cookie的代码修改如下 res.cookie('loggedIn', true, { httpOnly: true, sameSite: 'Strict', secure: process.env.NODE_ENV === 'production' }); res.cookie('isAdmin', isAdministrateur, { httpOnly: true, sameSite: 'Strict', secure: process.env.NODE_ENV === 'production' }); res.cookie('isClient', isClient, { httpOnly: true, sameSite: 'Strict', secure: process.env.NODE_ENV === 'production' });
httpOnly:防止前端JS读取Cookie,降低XSS风险sameSite: 'Strict':防止CSRF攻击secure:生产环境下仅通过HTTPS传输Cookie
修改后的核心代码示例
const express = require('express'); const path = require('path'); const app = express(); // 静态资源配置(仅暴露指定目录) app.use(express.static("style")); app.use(express.static(path.join(__dirname, 'public'))); // Logout路由 app.get('/logout', (req, res) => { res.clearCookie('loggedIn'); res.clearCookie('isAdmin'); res.clearCookie('isClient'); res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); res.redirect('/login.html'); }); // Login路由(保持原有逻辑) app.post('/login', async (req, res) => { const { username, password } = req.body; if (!username || !password) { return res.status(400).json({ message: "Veuillez fournir un nom d'utilisateur et un mot de passe." }); } const query = "SELECT * FROM users WHERE username = ? AND password = ?"; try { const [rows, fields] = await pool.execute(query, [username, password]); if (rows.length === 0) { return res.status(401).json({ message: "Nom d'utilisateur ou mot de passe incorrect." }); } const user = rows[0]; const isAdministrateur = user.administrateur === 1; const isClient = user.client === 1; // 带安全属性的Cookie设置 res.cookie('loggedIn', true, { httpOnly: true, sameSite: 'Strict', secure: process.env.NODE_ENV === 'production' }); res.cookie('isAdmin', isAdministrateur, { httpOnly: true, sameSite: 'Strict', secure: process.env.NODE_ENV === 'production' }); res.cookie('isClient', isClient, { httpOnly: true, sameSite: 'Strict', secure: process.env.NODE_ENV === 'production' }); if (isAdministrateur) { return res.redirect('/admin.html'); } else if (isClient) { return res.redirect('/client.html'); } else { return res.status(401).json({ message: "Ce compte n'est pas autorisé à se connecter." }); } } catch (error) { console.error(error); res.status(500).send("Une erreur est survenue lors de la connexion de l'utilisateur."); } }); // 权限验证中间件(保持原有逻辑) function isAuthenticated(req, res, next) { if (req.cookies.loggedIn) { next(); } else { res.redirect('/login.html'); } } function isAdmin(req, res, next) { if (req.cookies.isAdmin) { next(); } else { res.redirect('/login.html'); } } function isClient(req, res, next) { if (req.cookies.isClient) { next(); } else { res.redirect('/login.html'); } } // 带权限验证的页面路由(保持原有逻辑) app.get('/client.html', isAuthenticated, isClient, (req, res) => { res.sendFile(path.join(__dirname, 'client.html')); }); app.get('/admin.html', isAuthenticated, isAdmin, (req, res) => { res.sendFile(path.join(__dirname, 'admin.html')); }); // ...其他服务器启动代码
内容的提问来源于stack exchange,提问作者Miguel Vidal bravo jandia
相关产品推荐
相关产品推荐

