登录接口思路和开发

输入用户名和密码,返回token。这个token最好存储在redis中,设置过期时间2小时,过期后就不能使用。或者存储在数据库中。

只要是没有过期的token都可以作为调用接口的凭证。所以多个用户登录就有多个token返回。

调用接口的方式:

将token放在header中。

比如:

复制代码
// 以微信小程序 wx.request 为例[citation:5]
wx.request({
  url: 'https://api.example.com/data',
  method: 'POST',
  header: { // 此处设置请求头参数
    'Content-Type': 'application/json', // 告诉服务器发送的是JSON数据
    'Authorization': 'Bearer your_token_here', // 传递身份令牌
    'X-Custom-Header': 'CustomValue' // 传递任何自定义业务参数
  },
  data: { // 请求体数据,与header是独立的
    key1: 'value1',
    key2: 'value2'
  },
  success(res) {
    console.log(res.data);
  }
})

接口接收token:

复制代码
const express = require('express');
const app = express();
const PORT = 3000;

// 中间件:解析JSON请求体
app.use(express.json());

// 模拟用户数据库(实际项目中应使用数据库)
const mockUsers = [
  { id: 1, username: 'user1', role: 'admin' },
  { id: 2, username: 'user2', role: 'user' }
];

// 模拟令牌存储(实际项目中应使用Redis等)
const validTokens = new Map();

// 生成模拟令牌(实际项目中应使用JWT等)
function generateToken(userId) {
  const token = `token_${userId}_${Date.now()}`;
  validTokens.set(token, { 
    userId, 
    expiresAt: Date.now() + 3600000 // 1小时后过期
  });
  return token;
}

// 中间件:验证Bearer Token
function verifyToken(req, res, next) {
  // 1. 从Authorization头获取令牌
  const authHeader = req.headers['authorization'];
  
  if (!authHeader) {
    return res.status(401).json({
      code: 401,
      message: '未提供认证令牌',
      error: 'Missing Authorization header'
    });
  }
  
  // 2. 检查是否为Bearer Token
  const parts = authHeader.split(' ');
  if (parts.length !== 2 || parts[0] !== 'Bearer') {
    return res.status(401).json({
      code: 401,
      message: '令牌格式错误,应为 "Bearer <token>"',
      error: 'Invalid token format'
    });
  }
  
  const token = parts[1];
  
  // 3. 验证令牌有效性
  const tokenData = validTokens.get(token);
  
  if (!tokenData) {
    return res.status(401).json({
      code: 401,
      message: '令牌无效或已过期',
      error: 'Invalid token'
    });
  }
  
  // 4. 检查令牌是否过期
  if (Date.now() > tokenData.expiresAt) {
    validTokens.delete(token); // 清理过期令牌
    return res.status(401).json({
      code: 401,
      message: '令牌已过期',
      error: 'Token expired'
    });
  }
  
  // 5. 查找对应用户信息
  const user = mockUsers.find(u => u.id === tokenData.userId);
  if (!user) {
    return res.status(401).json({
      code: 401,
      message: '用户不存在',
      error: 'User not found'
    });
  }
  
  // 6. 将用户信息附加到请求对象,供后续中间件/路由使用
  req.user = user;
  req.token = token;
  
  // 令牌验证通过,继续下一个中间件/路由
  next();
}

// ==================== 接口路由 ====================

// 1. 登录接口(获取Token)
app.post('/api/auth/login', (req, res) => {
  const { username, password } = req.body;
  
  // 模拟用户验证(实际项目中应验证密码哈希)
  const user = mockUsers.find(u => u.username === username);
  
  if (!user) {
    return res.status(401).json({
      code: 401,
      message: '用户名或密码错误',
      error: 'Invalid credentials'
    });
  }
  
  // 生成令牌
  const token = generateToken(user.id);
  
  res.json({
    code: 200,
    message: '登录成功',
    data: {
      token,
      user: {
        id: user.id,
        username: user.username,
        role: user.role
      },
      expiresIn: 3600 // 令牌有效时间(秒)
    }
  });
});

// 2. 需要Token验证的受保护接口
app.get('/api/user/profile', verifyToken, (req, res) => {
  // 通过verifyToken中间件后,req.user已包含用户信息
  res.json({
    code: 200,
    message: '获取用户信息成功',
    data: {
      user: req.user,
      timestamp: new Date().toISOString()
    }
  });
});

// 3. 需要Token验证的POST接口(接收小程序请求)
app.post('/api/data/submit', verifyToken, (req, res) => {
  const requestBody = req.body;
  const customHeader = req.headers['x-custom-header'];
  
  res.json({
    code: 200,
    message: '数据接收成功',
    data: {
      receivedData: requestBody,
      customHeader: customHeader,
      processedBy: req.user.username,
      serverTime: new Date().toISOString()
    }
  });
});

// 4. 令牌刷新接口
app.post('/api/auth/refresh', verifyToken, (req, res) => {
  const oldToken = req.token;
  const newToken = generateToken(req.user.id);
  
  // 使旧令牌失效
  validTokens.delete(oldToken);
  
  res.json({
    code: 200,
    message: '令牌刷新成功',
    data: {
      token: newToken,
      expiresIn: 3600
    }
  });
});

// 5. 登出接口
app.post('/api/auth/logout', verifyToken, (req, res) => {
  validTokens.delete(req.token);
  
  res.json({
    code: 200,
    message: '登出成功'
  });
});

// 错误处理中间件
app.use((err, req, res, next) => {
  console.error('服务器错误:', err);
  res.status(500).json({
    code: 500,
    message: '服务器内部错误',
    error: process.env.NODE_ENV === 'development' ? err.message : undefined
  });
});

// 启动服务器
app.listen(PORT, () => {
  console.log(`✅ 服务器已
相关推荐
Mr_li11 小时前
NestJS 集成 TypeORM 的最优解
node.js·nestjs
UIUV13 小时前
node:child_process spawn 模块学习笔记
javascript·后端·node.js
前端付豪2 天前
Nest 项目小实践之注册登陆
前端·node.js·nestjs
天蓝色的鱼鱼2 天前
Node.js 中间层退潮:从“前端救星”到“成本噩梦”
前端·架构·node.js
codingWhat2 天前
uniapp 多地区、多平台、多环境打包方案
前端·架构·node.js
小p2 天前
nodejs学习: 服务器资源CPU、内存、硬盘
node.js
Mr_li2 天前
手摸手,教你如何优雅的书写 NestJS 服务配置
node.js·nestjs
QQ5110082852 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php
q***09802 天前
最新最详细的配置Node.js环境教程
node.js
WeiXin_DZbishe2 天前
基于django在线音乐数据采集的设计与实现-计算机毕设 附源码 22647
javascript·spring boot·mysql·django·node.js·php·html5