小白也能懂的 Token 认证:从原理到实战,用 Express 手把手教你做

小白也能懂的 Token 认证:从原理到实战,用 Express 手把手教你做

前后端分离的项目里,怎么确定 "你就是你"?比如你登录后想查看个人信息,服务器得知道 "现在发请求的人,确实是刚登录成功的那个用户"。以前用 Cookie-Session 的方式,跨域的时候特别麻烦,而 Token 认证就没这问题,现在几乎成了主流。今天就用大白话讲清楚 JWT(最常用的 Token 格式)是啥,再结合 Express 代码,教你搭一个能直接用的认证系统。

一、先搞懂:JWT 到底是个啥?

简单说,JWT 就是一串 "加密的身份小纸条"。服务器给你发这张纸条,你之后每次找服务器要东西,都得带上它 ------ 服务器不用记你的信息,只要看这张纸条对不对,就知道你是不是合法用户。

1. JWT 长啥样?三段式字符串而已

一个完整的 JWT 是这样的,用.分成三部分,比如:

plaintext

复制代码
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInVzZXJuYW1lIjoidGVzdHVzZXIiLCJpYXQiOjE3MTY2NTM0MDksImV4cCI6MTcxNjY1NzAwOX0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

这三部分各有各的用,咱们用 "快递包裹" 打比方,一下子就懂了:

部分 大白话作用 里面存啥(举例子) 能不能随便看?
Header(头部) 告诉大家 "我是 JWT,用 XX 方法加密的" {"alg":"HS256","typ":"JWT"} 能(Base64 编码,不是加密)
Payload(载荷) 存你的身份信息(比如 "你是谁,ID 多少") {"userId":1,"username":"testuser"} 能(同上,千万别存密码
Signature(签名) 防止纸条被篡改(服务器的 "防伪标志") 用密钥算出来的加密串(外人解不开) 不能(核心防伪部分)

2. JWT 怎么工作?就三步

整个认证流程特别简单,跟你去银行办事差不多:

  1. "办卡"(登录) :你带身份证(用户名 / 密码)去银行(服务器),银行核实后,给你一张银行卡(JWT Token);
  2. "用卡"(发请求) :之后你每次去银行办事(访问接口),都得带上这张卡(在请求头里带 Token);
  3. "验卡"(验证) :银行看一眼你的卡是不是真的、有没有过期(服务器验证 Token),没问题就给你办事(返回数据),有问题就赶你走(返回 401 错误)。

二、动手做:用 Express 搭 JWT 认证系统

接下来咱们照着代码一步步做,不用怕,都是基础操作。需要的工具就三个:express(搭服务器)、jsonwebtoken(生成 Token)、express-jwt(验证 Token)。

1. 先准备环境:装依赖

先建个文件夹,打开命令行,输入这两句,把需要的工具装好:

bash

csharp 复制代码
# 初始化项目(生成package.json,不用管它是啥,装依赖要用)
npm init -y

# 装核心工具:express(服务器)、jsonwebtoken(造Token)、express-jwt(验Token)
npm install express jsonwebtoken express-jwt

2. 核心代码拆解:从配置到接口

咱们把代码分成几块,每块都讲清楚干啥用的,跟着写就行。

第一步:搭好服务器架子,配基础设置

先把服务器启动起来,再配置好 "读 JSON 数据" 的功能(不然收不到前端发的用户名密码):

javascript

ini 复制代码
// 把装的工具引进来
const express = require('express');
const jwt = require('jsonwebtoken');
const { expressjwt: expressJWT } = require('express-jwt');

// 初始化服务器
const app = express();

// 关键:能读懂前端发的JSON格式数据(比如用户名密码)
app.use(express.json());

// 配置两个重要常量:
const SECRET_KEY = 'your-secret-key-keep-safe'; // 服务器的"密钥",验Token全靠它
const ALGORITHM = 'HS256'; // 加密方法(不用改,就用这个)

⚠️ 重点提醒SECRET_KEY 就像你家的钥匙,绝对不能写死在代码里!正式项目里要存在 "环境变量" 里(比如用 dotenv 工具),不然别人拿到代码,就能伪造你的 Token 了。

第二步:配 "全局验 Token" 中间件

这个中间件的作用是:所有接口默认都要验 Token,除了登录接口(总不能登录也要 Token 吧,不然永远登不上)。

javascript

less 复制代码
app.use(expressJWT({
  secret: SECRET_KEY, // 用刚才的密钥验Token
  algorithms: [ALGORITHM] // 用刚才的加密方法
}).unless({ path: ['/login'] })); // 排除/login接口,不用验Token

简单说:以后不管访问/profile还是/dashboard,服务器都会先看你带的 Token 对不对;只有访问/login,才不用验。

第三步:写登录接口:给用户发 Token

登录是唯一不用验 Token 的接口,作用就是 "核实用户名密码,对了就发 Token"。

javascript

javascript 复制代码
// 模拟数据库(正式项目要连MySQL、MongoDB这些真数据库)
const users = [
  { id: 1, username: 'testuser', password: 'testpass' } // 测试账号
];

// 登录接口:POST请求(前端发数据过来)
app.post('/login', (req, res) => {
  // 1. 从前端拿用户名和密码(req.body就是前端发的JSON数据)
  const { username, password } = req.body;
  
  // 2. 查"数据库",看有没有这个用户,密码对不对
  const user = users.find(u => u.username === username && u.password === password);
  if (!user) { // 没找到用户,或密码错了
    return res.status(401).send('用户名或密码错啦!');
  }
  
  // 3. 密码对了,生成Token
  const token = jwt.sign(
    // 第一部分:存用户身份信息(别存密码!谁都能解开)
    { userId: user.id, username: user.username },
    // 第二部分:用服务器密钥加密
    SECRET_KEY,
    // 第三部分:配置(Token有效期1小时,过了就得重新登录)
    { 
      expiresIn: '1h', 
      algorithm: ALGORITHM
    }
  );
  
  // 4. 把Token发给前端
  res.json({
    message: '登录成功!',
    token: token // 前端要把这个Token存起来(比如存在localStorage里)
  });
});

⚠️ 安全提醒 :示例里密码是明文存的,正式项目绝对不能这么干!要先用bcrypt这种工具把密码 "哈希"(变成一串乱码),存数据库里;验证的时候,再用工具把前端传的密码和哈希后的密码比对。

第四步:写受保护的接口:只有带正确 Token 才能访问

这些接口需要验 Token,验过了才能返回数据。而且验过之后,服务器能从 Token 里读出用户信息(比如用户 ID)。

javascript

javascript 复制代码
// 个人资料接口(只有登录后才能看)
app.get('/profile', (req, res) => {
  // req.auth里就是从Token里解析出来的用户信息(userId、username)
  res.json({
    message: '这是你的个人资料页,别人看不了!',
    user: req.auth // 把用户信息返回给前端
  });
});

// 仪表盘接口(同理,需要Token)
app.get('/dashboard', (req, res) => {
  res.json({
    message: '这是你的专属仪表盘',
    user: req.auth,
    data: '只有你能看到的数据(比如你的订单、收藏)'
  });
});
第五步:处理 "Token 验证失败" 的情况

比如 Token 过期了、Token 是伪造的,服务器得告诉前端 "咋回事",不能直接报错。

javascript

javascript 复制代码
app.use((err, req, res, next) => {
  // 如果是Token验证失败的错误
  if (err.name === 'UnauthorizedError') {
    return res.status(401).send({
      message: 'Token有问题!',
      detail: err.message // 具体啥问题(比如"Token过期了""签名不对")
    });
  }
  // 其他服务器错误(比如代码写错了)
  res.status(500).send('服务器出小问题啦,稍后再试~');
});

常见的 Token 错误:

  • jwt expired:Token 过期了,让用户重新登录;
  • invalid signature:Token 是假的,可能有人在搞事;
  • invalid token:Token 格式错了,比如前端没加 "Bearer" 前缀。
第六步:启动服务器,准备测试

最后一步,让服务器跑起来,监听 3000 端口:

javascript

javascript 复制代码
app.listen(3000, () => {
  console.log('服务器跑起来啦!地址:http://localhost:3000');
  console.log('测试步骤:');
  console.log('1. 先登录拿Token:发POST请求到 /login,带 {"username":"testuser","password":"testpass"}');
  console.log('2. 再访问受保护接口:发GET请求到 /profile 或 /dashboard,请求头带 Authorization: Bearer 你的Token');
});

到这里,代码就写完了!接下来咱们测试一下,看看好不好使。

三、测试:用 Postman 实操(小白也会)

Postman 是个测试接口的工具,下载下来打开就行,不用注册。

第一步:登录拿 Token

  1. 打开 Postman,选择 "POST" 方法,输入地址:http://localhost:3000/login

  2. 点击 "Body",选择 "raw",再选 "JSON" 格式;

  3. 输入下面的内容(测试账号密码):

    json

    json 复制代码
    {
      "username": "testuser",
      "password": "testpass"
    }
  4. 点击 "Send",右边会返回结果,里面有个token字段,把这串长长的字符复制下来(这就是你的 Token)。

第二步:用 Token 访问受保护接口

  1. 新建一个请求,选择 "GET" 方法,输入地址:http://localhost:3000/profile

  2. 点击 "Headers",添加一行:

    • Key:写 Authorization(注意首字母大写)
    • Value:写 Bearer 你刚才复制的Token(注意 "Bearer" 后面有个空格,别漏了)
  3. 点击 "Send",右边会返回你的个人信息,说明认证成功了!

如果没带 Token,或者 Token 错了,右边会返回 "Token 有问题",这就对了 ------ 说明我们的认证起作用了。

四、JWT 认证的优缺点:别光用,得知道好坏

优点:为啥大家都用 JWT?

  1. 服务器不用记东西:服务器不用存你的会话信息,不管多少人登录,都不影响性能,适合多台服务器一起用(比如淘宝的服务器有几百台,总不能每台都记你的信息吧);
  2. 跨域方便:Cookie 跨域特别麻烦,Token 直接放请求头里,不管前端后端在不在一个域名下,都能正常用;
  3. 简单轻量:Token 字符串不长,传起来快,不占带宽。

缺点:别踩坑!

  1. Token 不能主动作废:比如你登录后退出了,但 Token 没过期,别人拿到你的 Token 还是能访问接口。解决办法是搞个 "黑名单",把退出的 Token 存进去,服务器验证前先查黑名单;
  2. 不能存敏感信息:Payload 部分是 Base64 编码,不是加密,随便找个 Base64 解码工具就能解开,所以绝对不能存密码、手机号这些隐私数据;
  3. 有效期难平衡:有效期设太长,不安全;设太短,用户老得重新登录,体验差。解决办法是搞 "刷新 Token"------ 短 Token(1 小时)用来访问接口,长 Token(7 天)用来换短 Token,用户不用频繁登录。

正式项目里要注意的点(避坑指南)

  1. 密钥要安全:用随机生成的长字符串(比如 32 位),存在环境变量里,别写代码里;
  2. 密码要哈希 :用bcrypt工具处理密码,别存明文;
  3. 用 HTTPS:Token 在网上传的时候,要用 HTTPS 加密,不然别人能偷你的 Token;
  4. 加权限控制 :比如管理员和普通用户看到的内容不一样,可以在 Token 里加个role字段(比如"role":"admin"),接口里判断角色给不同数据;
  5. 处理 Token 过期:前端要监听 401 错误,Token 过期了就跳登录页,或者用刷新 Token 自动续期。

五、总结

其实 JWT 认证没那么复杂,核心就是 "发 Token - 带 Token - 验 Token" 这三步。今天咱们从原理讲到代码,再到测试,小白也能跟着做出来。

正式项目里,重点关注安全问题:密钥要藏好、密码要哈希、用 HTTPS、处理 Token 过期。只要把这些细节做好,JWT 就能帮你安全地识别用户身份,让你的项目更靠谱。

希望这篇文章能帮你搞懂 Token 认证,下次再遇到类似需求,就能轻松搞定啦!

相关推荐
间彧5 小时前
Spring IoC容器解决循环依赖的三级缓存机制详解
后端
间彧5 小时前
Spring IoC详解与应用实战
后端
junnhwan5 小时前
【苍穹外卖笔记】Day04--套餐管理模块
java·数据库·spring boot·后端·苍穹外卖·crud
间彧5 小时前
Java NPE异常详解
后端
无责任此方_修行中5 小时前
我的两次 Vibe Coding 经历,一次天堂,一次地狱
后端·node.js·vibecoding
想想就想想5 小时前
深度分页介绍及优化建议:从原理到实战的全链路解决方案
后端
程序员清风5 小时前
Dubbo RPCContext存储一些通用数据,这个用手动清除吗?
java·后端·面试
南瓜小米粥、6 小时前
从可插拔拦截器出发:自定义、注入 Spring Boot、到生效路径的完整实践(Demo 版)
java·spring boot·后端
Huangmiemei9116 小时前
Spring Boot项目的常用依赖有哪些?
java·spring boot·后端