本文目录导读:

- 核心架构分层
- 技术选型建议
- 核心数据模型设计(以关系型数据库为例)
- 核心代码结构骨架(以 Node.js + Express/TypeScript 为例,通用逻辑)
- 关键代码逻辑流(伪代码 + 核心实现)
- 安全增强 Checklist
- 总结:你搭建的这个脚手架能干什么?
搭建一个用户认证脚手架是后端开发中的核心基础工作,一个好的认证脚手架应该具备可扩展性(方便接入OAuth、OIDC)、安全性(防CSRF、防爆破)以及易用性(Session或JWT切换方便)。
下面我为你整理一套通用且生产级的认证脚手架搭建方案,以 前后端分离 架构为例,涵盖核心概念、技术选型与代码骨架。
核心架构分层
一个标准的认证模块通常分为三层:
- 入口层(Controller/API):处理登录、登出、注册、Token刷新等HTTP请求。
- 业务层(Service):包含核心认证逻辑(密码加密、Token生成、验证、Session管理)。
- 数据层(Repository/DAO):操作用户表、Token黑名单表、OAuth客户端表等。
技术选型建议
| 组件 | 推荐方案 | 说明 |
|---|---|---|
| 后端语言 | Java (Spring Boot), Node.js (Nest.js), Go (Gin), Python (FastAPI) | 选择一个你熟悉的生态 |
| 认证协议 | JWT (JSON Web Token) | 无状态、适合微服务和移动端,需要配合黑名单处理登出 |
| 密码存储 | bcrypt 或 Argon2 | 永远不要用MD5/SHA,必须加盐(Salt) |
| 访问控制 | RBAC (基于角色的访问控制) | 角色如 ADMIN, USER, GUEST |
| 安全防护 | CORS, Rate Limiting, CSRF Token (如用Cookie) | 防止跨域攻击和暴力破解 |
核心数据模型设计(以关系型数据库为例)
这是基础,建议一开始就设计好。
-- 1. 用户表
CREATE TABLE `users` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`username` VARCHAR(50) UNIQUE NOT NULL,
`email` VARCHAR(100) UNIQUE NOT NULL,
`password_hash` VARCHAR(255) NOT NULL, -- bcrypt加密后的结果
`role` ENUM('ADMIN', 'USER') DEFAULT 'USER',
`is_active` BOOLEAN DEFAULT TRUE,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 2. Token黑名单表(登出/撤销JWT用)
CREATE TABLE `token_blacklist` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`jti` VARCHAR(255) UNIQUE NOT NULL, -- JWT的唯一ID
`expires_at` TIMESTAMP NOT NULL, -- 该JWT的过期时间
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
核心代码结构骨架(以 Node.js + Express/TypeScript 为例,通用逻辑)
目录结构建议:
src/ ├── auth/ │ ├── auth.controller.ts # 路由处理器 │ ├── auth.service.ts # 业务逻辑 │ ├── auth.module.ts # 模块组织 │ ├── strategies/ │ │ └── jwt.strategy.ts # JWT验证策略 │ ├── guards/ │ │ ├── jwt-auth.guard.ts # 全局JWT守卫 │ │ └── roles.guard.ts # 角色守卫 │ └── dto/ │ ├── login.dto.ts │ └── register.dto.ts ├── common/ │ ├── decorators/ │ │ ├── current-user.decorator.ts # 获取当前请求用户 │ │ └── roles.decorator.ts │ └── filters/ │ └── http-exception.filter.ts # 统一异常处理 └── app.module.ts
关键代码逻辑流(伪代码 + 核心实现)
用户注册
async register(registerDto: RegisterDto) {
// 1. 检查用户名/邮箱是否已存在
const existingUser = await this.userRepo.findOne({
where: { email: registerDto.email }
});
if (existingUser) throw new ConflictException('用户已存在');
// 2. 使用 bcrypt 哈希密码(永远不要明文存储)
const saltRounds = 10;
const passwordHash = await bcrypt.hash(registerDto.password, saltRounds);
// 3. 创建用户
const newUser = this.userRepo.create({
...registerDto,
passwordHash, // 只存hash
});
return this.userRepo.save(newUser);
}
用户登录 & 发放 JWT Token
async login(loginDto: LoginDto) {
// 1. 获取用户
const user = await this.userRepo.findOne({ where: { email: loginDto.email } });
if (!user) throw new UnauthorizedException('用户名或密码错误'); // 注意:不要泄露是用户名还是密码错误
// 2. 验证密码(bcrypt.compare)
const isValid = await bcrypt.compare(loginDto.password, user.passwordHash);
if (!isValid) throw new UnauthorizedException('用户名或密码错误');
// 3. 生成 JWT Token
const payload = {
sub: user.id, // 标准字段:用户ID
email: user.email,
role: user.role,
jti: uuidv4() // JWT唯一ID,用于黑名单撤销
};
const accessToken = this.jwtService.sign(payload, {
expiresIn: '15m' // Access Token 过期时间短,15分钟
});
const refreshToken = this.jwtService.sign(
{ sub: user.id, jti: uuidv4() },
{ expiresIn: '7d' } // Refresh Token 过期时间长,7天
);
return { accessToken, refreshToken };
}
JWT 验证中间件(Guard/Interceptor)
这是最关键的安全环节,每次请求受保护的API时,拦截器都会运行以下逻辑:
async validateRequest(request: Request) {
// 1. 从 Header 提取 Token:Authorization: Bearer <token>
const token = extractTokenFromHeader(request);
if (!token) throw new UnauthorizedException('缺少认证信息');
try {
// 2. 验证 Token 签名和是否过期(由 JWT 库自动完成)
const payload = this.jwtService.verify(token);
// 3. 【安全增强】检查 Token 是否已被撤销(查询黑名单表)
const isBlacklisted = await this.blacklistRepo.findOne({
where: { jti: payload.jti }
});
if (isBlacklisted) throw new UnauthorizedException('Token 已被撤销');
// 4. 将用户信息注入到请求对象中
request.user = payload;
return true;
} catch (error) {
throw new UnauthorizedException('Token 无效或已过期');
}
}
刷新 Token
当 Access Token 过期时,客户端用它来获取新的短期令牌。
async refreshTokens(refreshToken: string) {
try {
// 1. 验证 Refresh Token 的有效性
const payload = this.jwtService.verify(refreshToken);
// 2. 颁发新的 Access Token
const newAccessPayload = {
sub: payload.sub,
email: payload.email,
role: payload.role,
jti: uuidv4()
};
const newAccessToken = this.jwtService.sign(newAccessPayload, {
expiresIn: '15m'
});
return { accessToken: newAccessToken };
} catch (error) {
throw new UnauthorizedException('Refresh Token 过期,请重新登录');
}
}
登出
由于 JWT 是无状态的,无法直接销毁,标准做法是将 Token 加入黑名单(有效期到 Token 本身过期为止)。
async logout(userId: number, jti: string, exp: number) {
// 1. 将 JWT 的 ID (jti) 加入黑名单表
await this.blacklistRepo.save({
jti: jti,
expiresAt: new Date(exp * 1000) // 转换时间戳
});
// 2. 如果使用 Refresh Token,也应将其加入黑名单或直接从客户端清除
return { message: '登出成功' };
}
安全增强 Checklist
搭建完基础脚手架后,建议立即加上以下安全措施:
- CORS 配置(仅白名单你的前端域名):
app.enableCors({ origin: 'https://你的前端域名.com' }); - 速率限制(防止暴力破解):
- 登录接口:同一 IP 1分钟最多尝试5次。
- 注册接口:同一 IP 1小时最多注册3次。
- 密码策略校验:
至少8位,包含大小写字母、数字、特殊字符。
- 环境变量:
- 永远不要将
JWT_SECRET、数据库密码写在代码里,使用.env文件或配置中心。
- 永远不要将
- 日志审计:
记录每次登录(成功/失败)、登出、敏感信息修改的日志。
你搭建的这个脚手架能干什么?
搭建完成后,你的系统将具备以下能力:
- 基于 JWT 的认证:安全、无状态、支持分布式。
- 基于 RBAC 的授权:可以区分普通用户和管理员。
- Token 刷新机制:用户无需频繁重新输入密码。
- 安全的登出机制:通过黑名单使 JWT 失效。
- 防暴力破解 & 防重放攻击:通过 Rate Limiting 和
jti验证。
如果你想针对特定语言(如 Java Spring、Go、Python)获取更详细的代码示例,可以告诉我,我可以为你进一步细化。