关注

⚡后端安全基石:JWT 原理与身份验证实战

大家好,我是大布布将军。

在你的 BFF 服务中,你不可能让所有人都能调用 /orders/list 接口。我们需要一个机制来验证用户的身份和权限,这个机制在现代 Web 应用中,几乎都基于 JWT (JSON Web Token)

本篇,我们将深入 JWT 的原理,并学习如何在 Node.js 中实现一个安全的注册和登录流程。

1. 什么是 JWT?——无状态的身份证明

JWT 是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在双方之间安全地传输信息。

核心关键词:无状态 (Stateless)。

传统的 Session/Cookie 模式需要在服务器端存储用户的会话信息(有状态)。而 JWT 的所有信息都编码在 Token 中,服务器无需存储 Session,极大提高了 Node.js 服务的可扩展性集群化能力

一个 JWT 通常由三部分组成,用点号(.)分隔:

Header.Payload.Signature\text{Header} . \text{Payload} . \text{Signature}Header.Payload.Signature

部分内容作用
Header (头部)包含 Token 类型(JWT)和所使用的加密算法(如 HMAC SHA256)。告诉接收方如何解析和验证 Token。
Payload (载荷)存放实际的声明信息(Claims),如用户 ID (userId)、角色 (role)、Token 过期时间 (exp)。存放用户的身份信息。
Signature (签名)使用 Header 和 Payload 结合一个只有服务器知道的密钥 (Secret Key) 进行加密计算得出的字符串。防止数据被篡改。 如果有人修改了 Payload,签名就会失效。

2. 实践项目:注册、登录与 Token 校验

我们使用 Node.js 中常用的 jsonwebtoken 库来实现这套流程。

步骤一:用户注册与密码安全

在用户注册时,我们绝对不能明文存储密码。我们需要使用 哈希算法(如 bcrypt)对密码进行单向加密。

TypeScript

// 📁 src/auth/auth.service.ts

import * as bcrypt from 'bcrypt';
import { Injectable } from '@nestjs/common';
import { UserService } from '../user/user.service'; // 假设我们有用户服务操作数据库

@Injectable()
export class AuthService {
    
    // 密码加密存储
    async register(username: string, password_plain: string): Promise<User> {
        // 1. 生成盐值 (Salt)
        const salt = await bcrypt.genSalt(); 
        // 2. 将密码和盐值进行哈希
        const hashedPassword = await bcrypt.hash(password_plain, salt); 

        // 3. 将用户名和哈希后的密码存储到数据库
        return this.userService.createUser(username, hashedPassword);
    }
}
步骤二:用户登录与 JWT 生成

用户登录成功后,我们需要为他生成一个 JWT Token,并返回给前端。

TypeScript

// 📁 src/auth/auth.service.ts (续)

import * as jwt from 'jsonwebtoken';
// 假设你的密钥存储在环境变量中
const JWT_SECRET = process.env.JWT_SECRET || 'YOUR_UNSAFE_SECRET_KEY'; 
const JWT_EXPIRES_IN = '1d'; // Token 1天后过期

async login(username: string, password_plain: string): Promise<string> {
    const user = await this.userService.findUserByUsername(username);
    if (!user) throw new Error('用户不存在');

    // 1. 验证密码:将用户输入的明文密码与数据库中的哈希值进行比对
    const isMatch = await bcrypt.compare(password_plain, user.hashedPassword);
    if (!isMatch) throw new Error('密码错误');

    // 2. 构造 Payload (载荷)
    const payload = { 
        userId: user.id, 
        role: user.role 
    }; 
    
    // 3. 生成 JWT Token 并签名
    const token = jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });

    // 4. 返回 Token(前端会将其存储在 LocalStorage 或 Cookie 中)
    return token; 
}
步骤三:身份验证中间件/守卫(Token 校验)

在 BFF 层,我们需要在每一个受保护的 API 接口前,校验前端请求头中携带的 Token 是否有效。

TypeScript

// 📁 src/middleware/auth.middleware.ts (NestJS Guard 或 Express Middleware)

import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
// ... 其他依赖

@Injectable()
export class AuthGuard implements CanActivate {
    canActivate(context: ExecutionContext): boolean {
        const request = context.switchToHttp().getRequest();
        const authHeader = request.headers.authorization; 

        if (!authHeader || !authHeader.startsWith('Bearer ')) {
            throw new UnauthorizedException('请求未携带 Token 或格式错误');
        }
        
        const token = authHeader.substring(7); // 提取 Token(去掉 "Bearer ")

        try {
            // 1. 验证签名和过期时间
            const payload = jwt.verify(token, JWT_SECRET) as { userId: number, role: string };
            
            // 2. 将用户信息附加到请求对象上,供 Controller/Service 使用
            request.user = payload; 
            
            return true; // 验证通过,允许访问 Controller
        } catch (error) {
            // 签名错误或 Token 过期
            throw new UnauthorizedException('Token 无效或已过期');
        }
    }
}

3. 安全性考量:JWT 的缺点

虽然 JWT 很强大,但它并非完美:

  • 无法主动失效: 一旦 Token 被签发,除非过期,否则服务器无法强制使其失效(除非引入 Redis 黑名单机制)。
  • Payload 不加密: Payload 只是被 Base64 编码,任何人都可以解析。因此,Payload 中绝不能存储敏感信息,如密码或密钥。

总结

掌握 JWT 是成为一名合格全栈工程师的必备技能。它让你能以可扩展、无状态的方式管理用户身份。通过 bcrypt 保证密码安全,通过 jsonwebtoken 签发和校验 Token,你的 BFF 服务就有了坚固的安全门。
在这里插入图片描述

下一篇,我们将进入工程化领域,学习 Docker 容器化。这是将我们写好的 Node.js 服务部署到生产环境的通行证。

转载自CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/scqgcy521/article/details/156057811

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--