导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

冷门技能

针对性攻坚(TODO)


持久登录

概述

持久登录允许用户即使在关闭浏览器后重新访问应用时也保持登录状态。为实现这一功能,我们将使用 Token (例如 JWT) 存储会话信息,并通过 HTTP-Only Cookie 保护 Token,以防止客户端 JavaScript 访问。

Untitled

实现步骤

  1. 用户登录
    1. 前端提交用户的登录信息(用户名和密码)到后端。
    2. 后端验证凭据成功后生成 JWT,将 JWT 存储在 HTTP-Only Cookie 中,以便浏览器自动在后续请求中发送。
  2. Token 持久化与验证
    1. 通过 HTTP-Only Cookie 持久化 Token,自动在后续请求中验证用户是否已登录。
    2. 在用户重新访问或刷新页面时,前端会在后端自动返回的 JWT 中找到用户会话信息,并更新应用状态。

示例代码

前端:Vue3 登录组件(Login.vue)

<template>
  <div>
    <h2>Login</h2>
    <form @submit.prevent="login">
      <input v-model="username" placeholder="Username" required />
      <input v-model="password" placeholder="Password" type="password" required />
      <button type="submit">Login</button>
    </form>
    <p v-if="error">{{ error }}</p>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      username: '',
      password: '',
      error: null,
    };
  },
  methods: {
    async login() {
      try {
        const res = await axios.post('/api/login', {
          username: this.username,
          password: this.password,
        }, { withCredentials: true });
        
        if (res.data.success) {
          this.$router.push('/home');
        }
      } catch (err) {
        this.error = 'Login failed. Please check your credentials.';
      }
    },
  },
};
</script>

后端:Express 路由与登录处理(auth.js)

const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const router = express.Router();

const SECRET_KEY = 'your_jwt_secret_key';  // 换成更安全的密钥
const COOKIE_NAME = 'auth_token';

router.post('/login', async (req, res) => {
    const { username, password } = req.body;

    // 假设此用户从数据库查询
    const user = { id: 1, username: 'test', passwordHash: await bcrypt.hash('password', 10) };

    if (user && await bcrypt.compare(password, user.passwordHash)) {
        const token = jwt.sign({ id: user.id, username: user.username }, SECRET_KEY, { expiresIn: '7d' });

        res.cookie(COOKIE_NAME, token, {
            httpOnly: true,
            secure: process.env.NODE_ENV === 'production',
            maxAge: 7 * 24 * 60 * 60 * 1000,  // 7 days
        });

        return res.json({ success: true, message: 'Login successful' });
    }

    return res.status(401).json({ success: false, message: 'Invalid credentials' });
});

module.exports = router;

验证用户会话的中间件(authMiddleware.js)

const jwt = require('jsonwebtoken');

const SECRET_KEY = 'your_jwt_secret_key';
const COOKIE_NAME = 'auth_token';

module.exports = (req, res, next) => {
    const token = req.cookies[COOKIE_NAME];
    
    if (token) {
        try {
            const user = jwt.verify(token, SECRET_KEY);
            req.user = user;
            next();
        } catch (err) {
            res.clearCookie(COOKIE_NAME);
            return res.status(401).json({ success: false, message: 'Token expired' });
        }
    } else {
        return res.status(401).json({ success: false, message: 'Unauthorized' });
    }
};

Express.js 中使用此中间件保护路由:

const express = require('express');
const authMiddleware = require('./authMiddleware');

const app = express();

app.use('/api/protected', authMiddleware, (req, res) => {
    res.json({ success: true, message: `Hello ${req.user.username}, you are authorized.` });
});

⭐️ 单点登录

在不同源的一个系统下,任意一个站点一个程序做了登录操作,其他站点或者程序同样处于登录状态的这种机制叫做单点登录机制。

Untitled

⭐ 说下单点登录