23 级山东大学软件学院创新实训 - 个人纪录(二)
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 # 启动脚本
架构优势
- 解耦彻底:接口路由、业务逻辑、数据模型完全分离
- 易于扩展:新增功能只需在对应层添加代码,不影响其他模块
- 团队协作:分工明确,便于多人并行开发
- 符合工程规范:贴近企业级后端开发标准,可读性与可维护性极高
二、核心功能开发:登录 / 注册接口实现
我独立完成了用户注册、用户登录两大核心 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}" # 哈希与盐拼接存储
设计说明
- 使用随机盐值(salt) 提升安全性,相同密码生成不同哈希
- 采用 SHA256 算法,满足实训项目安全要求
- 存储格式:
哈希值:盐值,登录时可拆分验证 - 预留升级空间:后期可直接替换为 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. 全局认证中间件(核心)
除登录 / 注册等开放接口外,所有接口必须经过中间件验证:
- 从请求头获取 Token
- 校验 Token 是否合法 / 过期
- 解析出
device_id,与 Redis 中存储的值比对 - 不一致 → 判定为被踢下线,返回 401 并拉黑
- 一致 → 放行请求
这套机制实现了:
- Token 过期自动拦截
- 异地登录强制下线
- 非法 Token 拒绝访问
- 全局统一权限拦截
六、接口测试:Postman 全场景验证
所有接口开发完成后,我使用 Postman 进行系统化接口测试,覆盖场景:
- 正常注册 / 用户名重复注册
- 正常登录 / 密码错误登录
- Token 过期访问
- 异地登录踢人测试
- 无效 Token、空 Token 访问
所有接口返回格式统一、状态码规范、异常处理完善,满足前后端联调标准。
七、本阶段核心成果
- 完成标准化后端分层架构,贴近企业级开发规范
- 实现登录 / 注册完整接口,通过 Postman 全面测试
- 自研密码哈希加密,支持盐值 + SHA256,安全不存明文
- 扩展 JWT 令牌,加入随机生成的 device_id 实现登录控制
- 基于 Redis + 中间件实现全局认证、踢人下线、黑名单机制
- 接口统一响应、异常捕获、权限拦截机制全部落地
八、阶段收获与思考
- 掌握 FastAPI + 分层架构 后端开发模式,理解企业级项目设计思想
- 深入理解 用户认证流程:密码加密、Token 签发、全局拦截、会话管理
- 学会使用 Redis 解决实际业务问题(唯一登录、设备校验)
- 提升接口设计与测试能力,能够独立完成后端核心模块开发
- 认识到安全设计的重要性:即使是简单项目,也必须避免明文密码、未授权访问
以下是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交付要求
提供完整的后端初始化代码
明确告诉我需要启动哪些服务(如 Redis、MySQL)及启动方式
提供 MySQL 连接配置说明
将所有建表 SQL 语句汇总到一个或多个 SQL 文件中,放在便于直接运行的目录下
其他说明
如使用 Redis(例如用于 Token 黑名单或刷新 Token),请一并告知配置方式
确保 JWT 的生成与验证逻辑正确实现
项目背景
文件路径:d:\LinguaSpark\fastAPI\database\import_vocabulary.py任务目标
编写一个 Controller(控制器),实现word表的增、删、查功能(改功能暂不实现)。后续phrases表和translations表的增删改查也会追加到同一个 Controller 中。一、查询功能(查)
前端可传入以下字段进行组合查询:
id、word、difficulty查询规则
场景 传入参数 查询行为 按 ID 查询 id=1,word和difficulty为空返回 id=1的单词按单词查询(精确) word="apple"返回 word字段为"apple"的全部记录(忽略id和difficulty)按单词查询(模糊) word="app"支持模糊匹配:可匹配 "apple"、"apply"等,只要单词中包含"app"即可(不限位置:开头、中间、结尾均可)按难度查询 difficulty="cet4"返回该难度下的全部单词 组合查询 difficulty="cet4"且word="apply"同时满足两个条件, id不参与查询注:查询结果为满足条件的所有记录,不限制数量。
二、增加功能(增)
传入参数:
word、difficulty业务逻辑:
检查在该
difficulty下是否已存在该word若不存在 → 新增记录
若已存在 → 直接返回(不新增,不报错)
说明:不要求返回特定提示,只需执行相应操作即可。
三、删除功能(删)
传入参数:一个包含
id的数组,例如[1, 2, 3]业务逻辑:
根据数组中提供的
id列表,批量删除对应的单词记录四、后续扩展说明
phrases表和translations表的增删改查功能,后续会追加到同一个 Controller 文件中本次请先实现
word表相关接口五、其他要求
基于现有项目结构(参考
import_vocabulary.py所在目录)进行开发遵循项目已有的代码风格和框架规范
项目背景
当前 Docker 容器创建时出现问题,需要调整数据导入相关的脚本和容器配置。任务目标
请按顺序完成以下三个任务,每完成一个任务请标记。任务一:重写数据库脚本(仅修改数据目录路径)
文件位置:
database/文件夹操作要求:
复制原脚本,新脚本命名规则:在原文件名后加
_for_docker后缀(用于与老脚本区分)大部分逻辑千万不能改动,仅允许修改一处:JSON 数据文件的导入目录
新目录路径:改为脚本所在目录的子目录
data示例:原脚本读取
/some/path/data.json→ 新脚本读取./data/数据文件禁止改动:其他任何实现逻辑(包括表结构、解析逻辑、写入逻辑等)均保持不变。
任务二:修改 Dockerfile 相关文件(调整脚本放置位置)
涉及文件:
Dockerfile、dockerfile.init操作要求:
在容器内新建一个文件夹:
data_import将任务一中生成的两个
_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文件夹下(本地)任务顺序 请按 一 → 二 → 三 依次执行,每完成一个任务标注清楚
更多推荐
所有评论(0)