LinguaSpark(灵语星火)智能外语学习平台第二阶段正式进入后端核心功能开发,我作为团队后端负责人,聚焦用户认证体系搭建、接口开发、项目架构规范、安全机制实现四大核心工作,完成了登录 / 注册全流程接口、密码加密、JWT 认证、Redis 登录冲突控制、统一拦截中间件,并基于 SpringBoot 思想规范了 FastAPI 后端项目分层架构,为平台后续功能开发奠定了稳定、安全、可扩展的基础。


一、后端架构规范:SpringBoot 风格分层设计

为了让项目结构清晰、职责分离、易于维护和协作,我参考 SpringBoot 分层架构思想,对 FastAPI 后端项目进行了标准化分层设计,明确每一层的职责边界:

app/
├── controllers/          # 控制器层 → 接收请求、返回响应
│   ├── auth_controller.py    # 登录、注册、token刷新接口
│   └── user_controller.py    # 用户信息管理接口
├── services/            # 服务层 → 核心业务逻辑实现
│   ├── auth_service.py       # 认证、加密、Token业务
│   └── user_service.py       # 用户数据操作业务
├── models/              # 模型层 → 数据结构与数据库映射
│   ├── user_models.py        # 用户请求/响应模型
│   └── database_models.py    # 数据库表模型
├── core/                # 核心层 → 全局配置与工具
│   ├── database.py           # 数据库连接
│   ├── redis_client.py       # Redis客户端
│   └── dependencies.py       # 依赖注入
├── __init__.py          
└── main.py              # 应用入口
run.py                  # 启动脚本

架构优势

  1. 解耦彻底:接口路由、业务逻辑、数据模型完全分离
  2. 易于扩展:新增功能只需在对应层添加代码,不影响其他模块
  3. 团队协作:分工明确,便于多人并行开发
  4. 符合工程规范:贴近企业级后端开发标准,可读性与可维护性极高

二、核心功能开发:登录 / 注册接口实现

我独立完成了用户注册、用户登录两大核心 API,并使用 Postman 完成全场景接口测试,确保接口稳定可用。

1. 注册接口

  • 接收用户名、密码、角色等参数
  • 校验用户名是否重复
  • 密码加密后存入数据库
  • 返回注册成功 / 失败信息

2. 登录接口

  • 校验用户名密码正确性
  • 后端自动随机生成 16 位唯一 device_id
  • 生成 JWT 访问令牌
  • 记录设备 ID 并写入 Redis
  • 处理账号异地登录冲突
  • 返回 Token 与用户基础信息

所有接口均遵循统一响应格式,前端可快速解析与处理异常。


三、密码安全:自定义 SHA256 哈希加密

考虑到项目当前阶段无高强度安全需求,我实现了轻量、安全的密码哈希存储方案,不存储明文密码

def get_password_hash(password: str) -> str:
    """生成密码哈希"""
    salt = secrets.token_hex(16)   # 生成随机盐值
    password_salt = password + salt
    # SHA256哈希计算
    hash_pw = hashlib.sha256(password_salt.encode()).hexdigest()
    return f"{hash_pw}:{salt}"     # 哈希与盐拼接存储

设计说明

  1. 使用随机盐值(salt) 提升安全性,相同密码生成不同哈希
  2. 采用 SHA256 算法,满足实训项目安全要求
  3. 存储格式:哈希值:盐值,登录时可拆分验证
  4. 预留升级空间:后期可直接替换为 bcrypt / Passlib 等高强度加密方案

四、JWT 认证机制:带设备 ID 的令牌设计

在标准 JWT 基础上,我扩展了设备 ID 字段,用于实现唯一登录、踢人下线功能:

access_token = AuthService.create_access_token(
    data={
        "sub": user.username,
        "device_id": device_id,  # 自定义:后端随机生成的16位设备标识
        "role": user.role
    }, 
    expires_delta=access_token_expires
)

Token 设计亮点

  • sub:用户名,用于标识用户
  • device_id登录时由后端随机生成的 16 位字符串,用于多设备登录冲突控制
  • role:用户角色,用于后续权限控制

五、Redis + 中间件:登录冲突控制 + 全局拦截

为实现 “同一账号只能在一台设备登录,后登踢先登”,我结合 Redis 与自定义中间件完成全局安全校验:

1. 登录逻辑

  • 用户登录成功后,后端自动生成 16 位随机 device_id
  • username → device_id 存入 Redis
  • 若账号已登录,自动覆盖 Redis 中的 device_id

2. 全局认证中间件(核心)

除登录 / 注册等开放接口外,所有接口必须经过中间件验证

  1. 从请求头获取 Token
  2. 校验 Token 是否合法 / 过期
  3. 解析出device_id,与 Redis 中存储的值比对
  4. 不一致 → 判定为被踢下线,返回 401 并拉黑
  5. 一致 → 放行请求

这套机制实现了:

  • Token 过期自动拦截
  • 异地登录强制下线
  • 非法 Token 拒绝访问
  • 全局统一权限拦截

六、接口测试:Postman 全场景验证

所有接口开发完成后,我使用 Postman 进行系统化接口测试,覆盖场景:

  • 正常注册 / 用户名重复注册
  • 正常登录 / 密码错误登录
  • Token 过期访问
  • 异地登录踢人测试
  • 无效 Token、空 Token 访问

所有接口返回格式统一、状态码规范、异常处理完善,满足前后端联调标准。


七、本阶段核心成果

  1. 完成标准化后端分层架构,贴近企业级开发规范
  2. 实现登录 / 注册完整接口,通过 Postman 全面测试
  3. 自研密码哈希加密,支持盐值 + SHA256,安全不存明文
  4. 扩展 JWT 令牌,加入随机生成的 device_id 实现登录控制
  5. 基于 Redis + 中间件实现全局认证、踢人下线、黑名单机制
  6. 接口统一响应、异常捕获、权限拦截机制全部落地

八、阶段收获与思考

  1. 掌握 FastAPI + 分层架构 后端开发模式,理解企业级项目设计思想
  2. 深入理解 用户认证流程:密码加密、Token 签发、全局拦截、会话管理
  3. 学会使用 Redis 解决实际业务问题(唯一登录、设备校验)
  4. 提升接口设计与测试能力,能够独立完成后端核心模块开发
  5. 认识到安全设计的重要性:即使是简单项目,也必须避免明文密码、未授权访问

以下是vibe coding主要的提示词

项目背景
请详细阅读项目任务书,目前处于第二阶段:初始化后端项目。

核心任务
实现基于 JWT 的用户认证模块,提供登录/注册 API,并连接 FastAPI 框架。

测试账号

  • 用户名:root

  • 密码:root

技术栈与中间件要求

  • 需要告知我需要开启哪些服务(如 Redis 等)

  • 使用 MySQL 作为数据库,需提供连接方式说明

  • 所有 SQL 语句需整理成独立的 SQL 文件,便于我直接执行

项目结构要求(请按模块划分)

请参考 Spring Boot 的包结构风格,按功能模块组织代码:

模块 说明 示例文件夹
路由层 专门管理 API 路由 routers/ 或 controller/
安全模块 集中管理权限、Token、JWT 相关逻辑 security/
业务模块 如登录、注册等具体功能 controller/ 或 handlers/

示例:登录相关逻辑放在 controller/login.py,安全相关放在 security/auth.py

交付要求

  1. 提供完整的后端初始化代码

  2. 明确告诉我需要启动哪些服务(如 Redis、MySQL)及启动方式

  3. 提供 MySQL 连接配置说明

  4. 将所有建表 SQL 语句汇总到一个或多个 SQL 文件中,放在便于直接运行的目录下

其他说明

  • 如使用 Redis(例如用于 Token 黑名单或刷新 Token),请一并告知配置方式

  • 确保 JWT 的生成与验证逻辑正确实现

项目背景
文件路径:d:\LinguaSpark\fastAPI\database\import_vocabulary.py

任务目标
编写一个 Controller(控制器),实现 word 表的增、删、查功能(改功能暂不实现)。后续 phrases 表和 translations 表的增删改查也会追加到同一个 Controller 中。

一、查询功能(查)

前端可传入以下字段进行组合查询:idworddifficulty

查询规则

场景 传入参数 查询行为
按 ID 查询 id=1word 和 difficulty 为空 返回 id=1 的单词
按单词查询(精确) word="apple" 返回 word 字段为 "apple" 的全部记录(忽略 id 和 difficulty
按单词查询(模糊) word="app" 支持模糊匹配:可匹配 "apple""apply" 等,只要单词中包含 "app" 即可(不限位置:开头、中间、结尾均可)
按难度查询 difficulty="cet4" 返回该难度下的全部单词
组合查询 difficulty="cet4" 且 word="apply" 同时满足两个条件,id 不参与查询

注:查询结果为满足条件的所有记录,不限制数量。

二、增加功能(增)

传入参数worddifficulty

业务逻辑

  1. 检查在该 difficulty 下是否已存在该 word

  2. 不存在 → 新增记录

  3. 已存在 → 直接返回(不新增,不报错)

说明:不要求返回特定提示,只需执行相应操作即可。

三、删除功能(删)

传入参数:一个包含 id 的数组,例如 [1, 2, 3]

业务逻辑

  • 根据数组中提供的 id 列表,批量删除对应的单词记录

四、后续扩展说明

  • phrases 表和 translations 表的增删改查功能,后续会追加到同一个 Controller 文件

  • 本次请先实现 word 表相关接口

五、其他要求

  • 基于现有项目结构(参考 import_vocabulary.py 所在目录)进行开发

  • 遵循项目已有的代码风格和框架规范

项目背景
当前 Docker 容器创建时出现问题,需要调整数据导入相关的脚本和容器配置。

任务目标
请按顺序完成以下三个任务,每完成一个任务请标记。

任务一:重写数据库脚本(仅修改数据目录路径)

文件位置database/ 文件夹

操作要求

  • 复制原脚本,新脚本命名规则:在原文件名后加 _for_docker 后缀(用于与老脚本区分)

  • 大部分逻辑千万不能改动,仅允许修改一处:JSON 数据文件的导入目录

  • 新目录路径:改为脚本所在目录的子目录 data

示例:原脚本读取 /some/path/data.json → 新脚本读取 ./data/数据文件

禁止改动:其他任何实现逻辑(包括表结构、解析逻辑、写入逻辑等)均保持不变。

任务二:修改 Dockerfile 相关文件(调整脚本放置位置)

涉及文件Dockerfiledockerfile.init

操作要求

  1. 在容器内新建一个文件夹:data_import

  2. 将任务一中生成的两个 _for_docker 脚本文件放入 data_import 文件夹中

注意:这是容器内的目录结构,不需要在本地项目文件夹中创建。

任务三:修改 Dockerfile(导入数据文件)

操作要求
将以下两类数据文件导入到容器内的 data 文件夹中:

  • JSON 文件(用于词汇导入)

  • XLSX 文件(用于故事导入)

最终容器内目录结构

/
├── data_import/          ← 存放两个 _for_docker 脚本
│   ├── xxx_for_docker.py
│   └── yyy_for_docker.py
└── data/                 ← 存放所有数据文件(JSON、XLSX)
    ├── *.json
    └── *.xlsx

重要提醒

项目 说明
data_import 和 data 文件夹 仅存在于 Docker 容器内部,不需要在本地文件系统中创建
新脚本文件 可以与老脚本文件放在同一 database 文件夹下(本地)
任务顺序 请按 一 → 二 → 三 依次执行,每完成一个任务标注清楚

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐