4.3 开发基础:登录权限与第一个模块¶
沿着脚手架示例,完成第一个真实业务功能¶
第一个模块的目标不是做得多,而是完整走通
页面能够打开,只说明前端存在;接口能够返回,只说明后端存在。一个真正完成的业务模块,需要把数据库、业务逻辑、接口、页面、登录权限和验证连接起来。
本节先理解脚手架已有的登录权限,再仿照 DemoItem 示例完成一个范围小的业务模块。不要重新发明登录系统,也不要一次开发整条复杂业务流程。
本节学习目标
理解当前用户身份和角色如何从登录页面传递到后端业务接口,选择一个简单业务模块,按照“数据表 → 后端 → 接口 → 页面 → 权限 → 验证”的顺序完成开发。
🎯 本节完成后,你要交付¶
| 成果 | 要求 |
|---|---|
| 登录权限验证记录 | 能说明登录状态保存在哪里,普通用户与管理员有什么差异 |
| 第一个业务模块 | 至少包含数据库、后端接口和可操作页面 |
| 模块接口说明 | 记录接口用途、角色、输入、成功结果和主要失败结果 |
| 模块测试记录 | 覆盖正常、未登录、无权限和输入错误中实际相关的场景 |
| Git 提交记录 | 一个提交只完成一个可以解释和验证的小任务 |
本节完成的是一个相对独立的基础模块,例如图书查询、活动管理、报修提交或商品管理。跨角色流转、审批、借还和库存变化等完整业务流程留到下一节。
🧭 第一步:选定一个“小而完整”的模块¶
使用上一节形成的第一模块任务卡,再确认它适合作为首次开发任务。
推荐选择¶
| 项目类型 | 适合的第一个模块 | 可以验证什么 |
|---|---|---|
| 图书管理 | 图书列表、查询和维护 | 分页、条件查询、管理员操作 |
| 活动报名 | 活动列表和活动维护 | 页面展示、状态字段、角色权限 |
| 宿舍报修 | 报修项目或报修类型管理 | 基础数据、表单校验、管理权限 |
| 校园集市 | 商品分类或商品信息 | 图片之外的基础增删改查 |
| 预约管理 | 服务项目管理 | 时间、状态和输入校验 |
第一模块最好满足:
- 对应一项已经确认的需求;
- 只涉及一张核心表或少量简单关联;
- 能够在一个页面完成主要操作;
- 有明确的普通用户或管理员权限;
- 一次课或一个小阶段能够验证;
- 暂时不依赖复杂状态流转和第三方服务。
本节完成标准¶
不要把“第一个模块”理解成复制一套通用 CRUD
如果需求只允许管理员创建、普通用户只能查看,就不要为普通用户增加编辑和删除。功能、字段和权限必须来自自己的需求与系统设计。
🔐 第二步:理解并验证已有登录权限¶
两套脚手架已经提供登录、注册和当前用户查询。本节不重写这些基础设施,而是先理解业务模块怎样使用当前用户身份。
主要位置:
| 作用 | 位置 |
|---|---|
| 登录、注册、当前用户接口 | backend/.../module/auth/ |
| JWT 校验和角色检查 | backend/.../security/ |
| 前端登录状态 | frontend/src/stores/userStore.js |
| 请求携带 Token | frontend/src/api/request.js |
| 页面路由权限 | frontend/src/router/index.js |
主要位置:
| 作用 | 位置 |
|---|---|
| 登录、注册、退出、当前用户 | controller/AuthServlet.java |
| 登录检查 | filter/LoginFilter.java |
| 管理员页面检查 | filter/AdminFilter.java |
| 前端请求和 401 处理 | src/main/webapp/js/common.js |
| 登录页面 | src/main/webapp/user/login.html |
权限不只是一张页面¶
至少区分三件事:
| 检查 | 要回答的问题 | 示例 |
|---|---|---|
| 是否登录 | 系统知道当前是谁吗? | 未登录不能查看个人记录 |
| 功能权限 | 当前角色能执行这个操作吗? | 普通用户不能新增系统分类 |
| 数据权限 | 当前用户能操作这条数据吗? | 用户只能修改自己提交的报修 |
页面隐藏按钮只能改善使用体验,不能代替后端校验。攻击者可以绕过页面直接调用接口。
先完成登录权限测试¶
| 场景 | 预期结果 |
|---|---|
| 正确账号登录 | 登录成功并能查询当前用户 |
| 错误密码 | 登录失败,不产生有效登录状态 |
| 未登录访问受限接口 | 返回 401 或明确的未登录结果 |
| 普通用户访问管理员功能 | 返回 403 或明确的权限不足结果 |
| 管理员访问管理功能 | 操作被允许 |
| 退出后再次访问 | 登录状态失效,需要重新登录 |
401 和 403 含义不同
401 表示尚未有效登录,403 表示已经识别身份但没有权限。页面可以给出不同提示,后端也应返回不同结果。
🔎 第三步:把 DemoItem 当作“路线图”¶
DemoItem 的价值不是业务内容,而是展示一个模块需要经过哪些层。先顺着示例代码走一遍,再创建自己的模块。
新业务模块应放入:
阅读示例时回答¶
- 表字段怎样映射到 Java 对象?
- 输入对象和输出对象是否分开?
- “数据不存在”在哪一层判断?
- 接口怎样限制管理员操作?
- 页面怎样调用查询、新增、修改和删除接口?
- 登录失效后页面怎样处理?
- 分页参数和结果采用什么格式?
不要复制后再逐字替换。先理解每个文件承担什么职责,只复用结构和已有公共能力。
🗃️ 第四步:先完成数据和接口约定¶
开始写页面前,先确认数据表和接口。否则页面字段很容易与后端、数据库互相不一致。
数据表检查¶
| 字段 | 类型 | 必填 | 业务含义 | 校验或约束 |
|---|---|---|---|---|
id |
【填写】 | 是 | 主键 | 自动生成 |
| 【业务字段】 | 【填写】 | 是 / 否 | 【填写】 | 【长度、范围】 |
status |
【填写】 | 是 | 【填写】 | 【允许值】 |
created_at |
【填写】 | 是 | 创建时间 | 自动记录 |
使用上一节建立的增量脚本创建或调整业务表。Spring Boot 路线继续追加新的 Flyway 迁移,不修改已经执行的 V1。
接口清单¶
| 功能 | 方法与路径 | 角色 | 输入 | 成功结果 | 主要失败 |
|---|---|---|---|---|---|
| 分页查询 | 【填写】 | 【填写】 | 页码、条件 | 列表和总数 | 参数错误 |
| 查询详情 | 【填写】 | 【填写】 | 对象 ID | 对象详情 | 数据不存在 |
| 新增 | 【填写】 | 【填写】 | 表单字段 | 新对象或成功结果 | 未登录、无权限、校验失败 |
| 修改 | 【填写】 | 【填写】 | ID、表单字段 | 修改后结果 | 数据不存在、状态不允许 |
| 删除或停用 | 【填写】 | 【填写】 | 对象 ID | 成功结果 | 无权限、对象正在使用 |
不是每个模块都必须有五个接口。根据真实需求删除不需要的操作,例如历史业务记录通常不应提供任意删除。
🧱 第五步:按后端分层逐步实现¶
建议按照“从数据库向接口”的顺序完成后端:
- 执行数据库脚本并检查表结构;
- 创建实体或数据对象;
- 完成数据访问;
- 完成业务逻辑和规则判断;
- 创建接口;
- 增加登录、角色和数据权限;
- 使用 Postman 或 Apifox 验证接口。
各层只负责自己的工作¶
| 层次 | 主要职责 | 不应承担 |
|---|---|---|
| Entity | 映射数据库字段 | 页面提示和复杂业务判断 |
| DTO/VO | 定义输入和输出 | 直接执行 SQL |
| Mapper/DAO | 查询和修改数据库 | 判断用户能否操作 |
| Service | 业务规则、状态和数据权限 | 生成页面 HTML |
| Controller/Servlet | 接收参数、调用服务、返回响应 | 堆积全部业务逻辑 |
当前用户不能来自前端信任¶
例如新增“我的报修”时,创建人应来自后端确认的当前用户:
如果模块只有管理员维护,也要在后端接口校验管理员角色,而不是只隐藏页面按钮。
不要顺手修改公共基础设施
优先复用脚手架的统一响应、全局异常、JWT 或 Session、分页对象和数据库工具。确需修改 AGENTS.md 中的禁区文件时,先说明当前能力为什么不能满足需求、会影响哪些已有功能,并请教师确认。
🖥️ 第六步:完成页面和前后端连接¶
后端接口验证通过后,再完成页面。
页面至少包含¶
- 页面标题和返回入口;
- 查询条件或主要操作;
- 列表、详情或表单;
- 加载状态;
- 空数据状态;
- 成功或失败提示;
- 根据角色显示的操作入口;
- 输入校验;
- 操作完成后的刷新或跳转。
两条技术路线¶
参考:
frontend/src/api/demoItem.js:封装业务请求;frontend/src/views/demo/:列表和表单页面;frontend/src/router/index.js:页面路由和前端访问控制;Loading.vue、Empty.vue、Pagination.vue:公共组件。
新模块至少保持“API 文件、页面、路由”职责分开,不在 Vue 页面中重复创建一套 Axios 配置。
参考:
src/main/webapp/js/common.js:统一请求和错误处理;src/main/webapp/admin/demo-items.html:列表和分页;src/main/webapp/admin/demo-item-form.html:新增与编辑;LoginFilter、AdminFilter:后端访问控制。
使用现有 API.request(),不要在每个页面重复处理基础路径、Cookie 和 401 跳转。
先完成最小页面,再改善样式
第一轮只要求能够查询、输入、提交和看到结果。确认数据和权限正确后,再统一布局、颜色和交互细节。
🧪 第七步:用四类场景验证模块¶
不要只验证“管理员新增成功”。
1. 正常场景¶
- 合法用户能够打开页面;
- 查询结果与数据库一致;
- 合法输入能够新增或修改;
- 刷新页面后结果仍然存在。
2. 输入和数据场景¶
- 必填字段为空;
- 字符串过长或数值越界;
- 查询不存在的 ID;
- 重复数据违反唯一规则;
- 空列表能够正常显示。
3. 登录和权限场景¶
- 未登录直接访问页面或接口;
- 普通用户直接调用管理员接口;
- 用户修改参数尝试操作他人数据;
- 退出登录后再次提交。
4. 运行和一致性场景¶
- 前端提示与接口结果一致;
- 接口字段与数据库字段一致;
- 操作失败后数据库没有错误变化;
- 后端日志没有新增异常;
- 原有登录和 DemoItem 示例没有被破坏。
模块验证记录¶
| 场景 | 操作步骤 | 预期结果 | 实际结果 | 证据 | 结论 |
|---|---|---|---|---|---|
| 正常新增 | 【填写】 | 【填写】 | 【填写】 | 页面/接口/数据库 | 通过/未通过 |
| 未登录访问 | 【填写】 | 返回 401 | 【填写】 | Network/接口 | 通过/未通过 |
| 普通用户越权 | 【填写】 | 返回 403 | 【填写】 | 接口响应 | 通过/未通过 |
| 输入错误 | 【填写】 | 明确提示,数据不变 | 【填写】 | 页面/数据库 | 通过/未通过 |
🤖 第八步:让 AI 一次完成一个小任务¶
不要直接要求:
先让 AI 阅读现状并制定计划:
确认方案后按小任务推进:
如果出现错误,提供复现步骤、预期结果、实际结果、浏览器 Network 和后端日志,让 AI 先定位原因,不要让它连续尝试大量无依据修改。
👀 第九步:审查并提交¶
模块运行成功后,再做一次代码审查:
- 是否符合需求和系统设计;
- 是否复用脚手架已有结构;
- 是否把业务逻辑堆在页面或 Controller;
- 是否信任前端提交的用户身份;
- 是否只有前端权限、缺少后端校验;
- 是否处理数据不存在和输入错误;
- 是否修改了无关文件或引入无用依赖;
- 是否具有可复现的验证证据。
提交前执行适合当前路线的构建或测试,并检查改动:
建议按小成果提交:
提交信息可以使用中文,但必须说明完成了什么。不要把未完成页面、调试输出和无关格式调整混在同一个提交中。
✅ 本节验收清单¶
- 第一个模块对应已确认需求;
- 模块范围小,可以独立运行和验证;
- 能说明 JWT 或 Session 怎样保存和传递登录状态;
- 能区分登录、功能权限和数据权限;
- 数据表和接口字段与系统设计一致;
- 后端按职责完成数据访问和业务逻辑;
- 当前用户身份由后端登录信息确定;
- 管理操作具有后端角色校验;
- 页面调用真实接口并读写数据库;
- 页面具有加载、空数据和失败反馈;
- 至少验证一个正常场景;
- 至少验证一个输入或边界场景;
- 未登录和越权操作得到正确拒绝;
- 操作失败时数据库保持正确;
- 原有登录和示例功能没有被破坏;
- 已保存验证记录和范围清楚的 Git 提交。
📝 总结¶
- 先理解登录链路:知道当前用户和角色怎样到达业务接口。
- 沿示例完成纵向模块:从数据表一直做到页面和验证。
- 权限以后端为准:页面隐藏按钮不能阻止越权调用。
- 一次完成一个小任务:后端、页面和测试可以分步提交。
- 完成必须有证据:页面、接口和数据库结果共同证明模块可用。