You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Express.js和Firebase构建安全的服务端认证系统?

问题根源

你的代码仅调用Firebase的signInWithEmailAndPassword完成认证,但没有在服务端为每个用户建立独立、隔离的会话,且未对会话做安全配置,导致同一网络下的设备能共享未受保护的认证状态。

安全服务端认证系统构建方案

1. 基于Cookie的会话管理(推荐)

核心逻辑

认证成功后,为每个用户生成唯一会话标识,绑定用户信息存储在服务端,并通过安全Cookie传递会话标识,确保每个设备的会话独立隔离。

示例代码

const { v4: uuidv4 } = require('uuid');
const redis = require('redis');
const client = redis.createClient();

// 登录接口
app.post('/logIn', async (req, res) => {
    const context = { error: false };
    let userCredential;
    try {
        userCredential = await signInWithEmailAndPassword(auth, req.body.email, req.body.password);
    } catch (err) {
        context.error = true;
        return res.render('auth/logIn.ejs', context);
    }

    // 生成唯一会话ID
    const sessionId = uuidv4();
    // 将用户ID与会话ID绑定,存入Redis并设置2小时过期时间
    await client.setEx(sessionId, 7200, userCredential.user.uid);

    // 设置安全Cookie
    res.cookie('sessionId', sessionId, {
        httpOnly: true,       // 禁止前端JS读取,防范XSS攻击
        secure: process.env.NODE_ENV === 'production', // 生产环境强制HTTPS传输
        sameSite: 'Strict',   // 防范CSRF攻击
        maxAge: 7200000       // 会话有效期2小时
    });

    return res.redirect('/');
})

2. 会话验证中间件

对需要认证的路由,添加中间件校验会话有效性,拦截未认证请求:

async function authenticate(req, res, next) {
    const sessionId = req.cookies.sessionId;
    if (!sessionId) {
        return res.redirect('/logIn');
    }

    // 从Redis获取绑定的用户ID
    const userId = await client.get(sessionId);
    if (!userId) {
        res.clearCookie('sessionId');
        return res.redirect('/logIn');
    }

    // 将用户ID挂载到req对象,供后续路由使用
    req.userId = userId;
    next();
}

// 示例:需要认证的首页路由
app.get('/', authenticate, (req, res) => {
    res.render('home.ejs');
});

3. 安全登出逻辑

登出时删除服务端会话记录,并清除客户端Cookie:

app.post('/logOut', async (req, res) => {
    const sessionId = req.cookies.sessionId;
    if (sessionId) {
        await client.del(sessionId);
    }
    res.clearCookie('sessionId');
    res.redirect('/logIn');
});

4. 无状态替代方案:JWT认证

若偏好无状态架构,可使用JWT(JSON Web Token)实现认证,同样通过HttpOnly Cookie传输:

const jwt = require('jsonwebtoken');

// 登录时生成JWT
app.post('/logIn', async (req, res) => {
    const context = { error: false };
    let userCredential;
    try {
        userCredential = await signInWithEmailAndPassword(auth, req.body.email, req.body.password);
    } catch (err) {
        context.error = true;
        return res.render('auth/logIn.ejs', context);
    }

    // 生成JWT,有效期2小时
    const token = jwt.sign(
        { userId: userCredential.user.uid },
        process.env.JWT_SECRET,
        { expiresIn: '2h' }
    );

    // 设置安全Cookie存储JWT
    res.cookie('token', token, {
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production',
        sameSite: 'Strict',
        maxAge: 7200000
    });

    return res.redirect('/');
})

// JWT验证中间件
function authenticateJWT(req, res, next) {
    const token = req.cookies.token;
    if (!token) {
        return res.redirect('/logIn');
    }

    jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
        if (err) {
            res.clearCookie('token');
            return res.redirect('/logIn');
        }
        req.userId = user.userId;
        next();
    });
}

5. 额外安全加固措施

  • 生产环境强制使用HTTPS,避免明文传输认证信息
  • 为登录接口添加速率限制,防范暴力破解
  • 用户修改密码时,强制失效原有会话/令牌
  • 若使用自定义用户系统,必须对密码进行哈希存储(Firebase已自动处理此步骤)

内容的提问来源于stack exchange,提问作者galdinotrashaj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 02:10:15