当前位置:首页 > 问答 > 正文

怎么实现登录不用数据库也能搞定,代码简单又实用分享

(引用来源:基于服务器端Session、客户端Token及文件存储的常见轻量级认证方案整合)

想做个简单的登录功能,但又嫌装数据库太麻烦?比如就是个个人小工具、毕业设计演示,或者一个用户量极小的内部应用,确实没必要上MySQL、Redis这些大家伙,不用数据库,登录功能照样能玩得转,而且代码可以非常简洁,下面就来分享几种简单实用的办法,咱们用最直白的思路和代码来说明。

第一种办法:用文件当数据库,配合服务器Session

这是最直接能想到的替代方案,既然数据库的本质就是存东西,那一个文本文件或者JSON文件也能存用户信息啊。

思路是这样的:

  1. 用户注册时,我们把用户名和密码(切记要加密!)写到一个文件里,比如叫 users.json
  2. 用户登录时,我们读取这个文件,核对输入的用户名和密码是否匹配。
  3. 如果匹配成功,就在服务器端创建一个Session,标记这个用户已经登录了。

这里的关键是Session,你可以把它理解成服务器给每个登录成功的用户发的一个“临时通行证”,服务器会把这个通行证编号(Session ID)通过Cookie告诉用户的浏览器,浏览器下次请求时带着这个编号,服务器就知道是谁了,用户信息存在服务器内存里,文件里只存永久的账号密码。

我们用Node.js和Express框架写个极简例子,一看就懂:

怎么实现登录不用数据库也能搞定,代码简单又实用分享

// 引入必要的模块
const express = require('express');
const session = require('express-session');
const fs = require('fs');
const app = express();
// 启用Session中间件(秘密密钥自己设一个)
app.use(session({
  secret: '你的秘密字符串',
  resave: false,
  saveUninitialized: false
}));
// 用于解析POST请求中的JSON数据
app.use(express.json());
// 注册接口
app.post('/register', (req, res) => {
  const { username, password } = req.body;
  // 1. 读取现有的用户文件(如果存在的话)
  let users = [];
  try {
    users = JSON.parse(fs.readFileSync('users.json'));
  } catch (error) {
    // 文件不存在也没关系,就当是空数组
  }
  // 2. 检查用户名是否已存在
  if (users.find(user => user.username === username)) {
    return res.status(400).send('用户名已存在');
  }
  // 3. 密码加密(这里用简单的哈希,实际项目要用bcrypt等强加密库)
  // 为了演示,我们假设有一个简单的哈希函数
  const hashedPassword = simpleHash(password);
  // 4. 保存新用户
  users.push({ username, password: hashedPassword });
  fs.writeFileSync('users.json', JSON.stringify(users, null, 2));
  res.send('注册成功!');
});
// 登录接口
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  // 1. 读取用户文件
  let users = [];
  try {
    users = JSON.parse(fs.readFileSync('users.json'));
  } catch (error) {
    return res.status(500).send('系统错误');
  }
  // 2. 查找用户并验证密码
  const user = users.find(u => u.username === username);
  if (user && user.password === simpleHash(password)) {
    // 3. 登录成功!把用户信息存到Session里
    req.session.userId = username; // 通常存用户ID,这里用用户名简化
    req.session.isLogin = true;
    return res.send('登录成功!');
  } else {
    res.status(401).send('用户名或密码错误');
  }
});
// 一个需要登录才能访问的页面
app.get('/profile', (req, res) => {
  if (req.session.isLogin) {
    res.send(`欢迎你,${req.session.userId}!`);
  } else {
    res.status(401).send('请先登录!');
  }
});
// 注销接口
app.post('/logout', (req, res) => {
  req.session.destroy();
  res.send('已退出登录');
});
// 一个简单的哈希函数示例(仅用于演示,不适用于生产环境)
function simpleHash(str) {
  // 生产环境请务必使用专业的密码哈希库,如 bcrypt
  let hash = 0;
  for (let i = 0; i < str.length; i++) {
    hash = ((hash << 5) - hash) + str.charCodeAt(i);
    hash |= 0; // 转换为32位整数
  }
  return hash.toString();
}
app.listen(3000, () => console.log('服务器在3000端口启动'));

这个例子的好处是逻辑清晰,Session由服务器管理,相对安全,缺点是如果服务器重启,内存里的Session就丢了,用户需要重新登录,对于小应用来说,这通常可以接受。

第二种办法:用Token,信息全放在客户端

这种方法更“无状态”,服务器完全不记录谁登录了,它的核心是Token(令牌)。

思路是这样的:

怎么实现登录不用数据库也能搞定,代码简单又实用分享

  1. 登录时,服务器核对用户名和密码(还是从文件读)。
  2. 核对成功,服务器生成一个Token,这个Token里其实就编码了用户信息(比如用户名),并且附带了数字签名,防止被篡改。
  3. 把这个Token发回给客户端(比如浏览器的LocalStorage里)。
  4. 客户端以后每次请求API,都在请求头里带上这个Token。
  5. 服务器收到Token,验证一下签名是否有效,如果有效就认为用户已登录,并从Token里解析出用户信息。

这种方法连服务器重启都不怕,因为登录状态全在客户端手里拿着,常用的Token标准是JWT(JSON Web Token)。

我们还是用Node.js写个概念性的例子,忽略掉JWT复杂的签名细节,用简化的思路表达:

const express = require('express');
const fs = require('fs');
const app = express();
app.use(express.json());
// 假设的Token生成与验证函数(真实项目请使用jsonwebtoken等成熟库)
function generateToken(username) {
  // 简单模拟:把用户名和一个过期时间拼起来,然后做个假签名
  const payload = { username, exp: Date.now() + (60 * 60 * 1000) }; // 过期时间1小时后
  const fakeSignature = 'signed_' + Buffer.from(JSON.stringify(payload)).toString('base64');
  return fakeSignature;
}
function verifyToken(token) {
  try {
    // 模拟验证签名和解码
    const decodedStr = Buffer.from(token.replace('signed_', ''), 'base64').toString();
    const payload = JSON.parse(decodedStr);
    // 检查过期时间
    if (payload.exp < Date.now()) {
      return null; // Token过期
    }
    return payload; // 返回Token里的信息
  } catch (e) {
    return null; // Token无效
  }
}
// 登录接口(注册接口和第一种方法类似,省略)
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  // ... 从文件读取用户并验证密码的代码同上 ...
  if (/* 验证成功 */) {
    // 生成Token并返回给客户端
    const token = generateToken(username);
    res.json({ success: true, token: token });
  } else {
    res.status(401).json({ success: false, message: '登录失败' });
  }
});
// 需要认证的接口
app.get('/api/data', (req, res) => {
  // 客户端需要在请求头里带上 Authorization: Bearer <token>
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1]; // 获取Bearer后面的Token
  if (!token) {
    return res.status(401).send('缺少Token');
  }
  const userData = verifyToken(token);
  if (userData) {
    // Token有效,userData里就有用户名等信息
    res.json({ message: `这是${userData.username}的私有数据` });
  } else {
    res.status(403).send('无效或过期的Token');
  }
});
app.listen(3000);

这种方法的优点是服务器轻松,扩展性好,缺点是Token一旦发出,在过期前服务器无法主动让它失效(除非引入额外的黑名单机制,但那又需要存储了)。

对于“不用数据库”的登录,核心就是找替代品来存用户凭证(文件)和管理登录状态(Session或Token)。

  • 文件+Session:简单直观,适合传统的网页应用,服务器有状态。
  • 文件+Token:更现代,适合前后端分离的API接口,服务器无状态。

选择哪种,看你的具体需求,无论哪种,都要牢记:密码绝不能明文存储,一定要用可靠的哈希算法(示例中的simpleHash仅为演示,实际请用bcryptargon2)进行加密,这样,即使文件被泄露,攻击者也很难反推出原始密码,这些方法在用户量小、安全性要求不是极端高的场景下,是完全可行且非常实用的。