# app-manage-demo **Repository Path**: dengkegit/app-manage-demo ## Basic Information - **Project Name**: app-manage-demo - **Description**: No description available - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-08 - **Last Updated**: 2026-09-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 应用管理系统(App Manage) 一个基于 **Vue 3 + Element Plus** 与 **Spring Boot + MyBatis-Plus** 的前后端分离应用管理系统,支持用户登录认证、Token 双刷新机制、双认证方式、动态菜单权限、修改密码、用户管理、应用管理及操作审计。 ## 技术栈 ### 前端 | 技术 | 版本 | 说明 | | --- | --- | --- | | Vue | 3.x | 渐进式框架 | | Element Plus | 2.x | UI 组件库 | | Vue Router | 4.x | 路由管理 | | Pinia | 2.x | 状态管理 | | Axios | 1.x | HTTP 请求 | | Vite | 5.x | 构建工具 | ### 后端 | 技术 | 版本 | 说明 | | --- | --- | --- | | Java | 8 | 开发语言 | | Spring Boot | 2.7.18 | 应用框架 | | MyBatis-Plus | 3.5.3.1 | ORM 框架 | | MySQL | 5.x | 数据库 | | JWT (jjwt) | 0.9.1 | 身份认证 | ## 功能特性 - ✅ **用户登录认证**:工号 + 密码登录,JWT Token 双 Token(Access + Refresh)机制 - ✅ **退出登录**:清除 Cookie 中的 Token 与前端 localStorage 缓存 - ✅ **Token 续期**:Refresh Token 刷新 Access Token - ✅ **前端 Token 自动刷新**:401 时自动用 Refresh Token 刷新并重放请求 - ✅ **修改密码**:登录用户可修改自己的密码,前后端双重密码强度校验 - ✅ **用户管理**:增删改查(工号、用户名、密码加密、角色) - ✅ **应用管理**:增删改查(英文名、中文名、管理员A/B、技术栈),支持后端分页 - ✅ **角色管理**:超级管理员、管理员、普通用户 - ✅ **操作审计**:独立页面展示应用表的增、删、改操作记录(工号、姓名、操作类型、时间、请求参数) - ✅ **动态菜单权限**:基于数据库表配置角色可访问页面,登录后动态控制菜单与路由拦截 - ✅ **应用操作权限控制**:超级管理员、管理员可操作所有应用;普通用户仅能操作自己是管理员A/B 的应用 - ✅ **双认证方式**:需认证接口支持 JWT Token(Cookie)与 Basic Auth 两种调用方式,兼容页面与服务间调用 - ✅ **注解式免认证白名单**:`@NoAuth` 注解声明无需鉴权的接口 - ✅ **跨域支持**:后端 CORS 配置 + 前端 Vite 代理 - ✅ **Cookie 存储 Token**:自动携带,HttpOnly 保护 - ✅ **完善的日志能力**:后端关键业务节点记录日志,滚动文件输出便于故障排查 ## 目录结构 ``` app-manage-demo/ ├── backend/ # 后端 Spring Boot 项目 │ ├── pom.xml │ └── src/main/ │ ├── java/com/example/appmanage/ │ │ ├── AppManageApplication.java │ │ ├── common/ # 统一返回、异常、常量 │ │ ├── config/ # CORS、MyBatis-Plus、拦截器配置 │ │ ├── controller/ # 控制器(auth/app/user/audit/menu) │ │ ├── dto/ # 请求/响应对象 │ │ ├── entity/ # 实体(User/App/OperationLog/RoleMenu) │ │ ├── mapper/ # Mapper 接口 │ │ ├── security/ # JWT 工具、拦截器、Basic Auth、@NoAuth、上下文 │ │ └── service/ # 服务接口与实现 │ └── resources/ │ ├── application.yml │ └── logback-spring.xml # 日志配置(控制台 + 滚动文件) ├── frontend/ # 前端 Vue 3 项目 │ ├── package.json │ ├── vite.config.js │ ├── index.html │ └── src/ │ ├── api/ # axios 封装与接口(auth/app/user/audit/menu) │ ├── layout/ # 布局组件(含动态菜单、用户信息展示) │ ├── router/ # 路由(含动态权限拦截) │ ├── store/ # Pinia 状态(含 localStorage 缓存) │ └── views/ # 页面(Login/App/User/AuditLog/Forbidden) ├── sql/ │ └── init.sql # 数据库初始化脚本 └── README.md ``` ## 快速开始 ### 环境要求 - JDK 1.8+ - Maven 3.6+ - Node.js 16+(推荐 18/20) - MySQL 5.x ### 1. 初始化数据库 执行 `sql/init.sql`: ```bash mysql -u root -p < sql/init.sql ``` 脚本会自动创建 `app_manage` 数据库、四张表(用户表、应用表、操作日志表、角色-菜单权限表)并插入初始账号与菜单配置。 > ⚠️ 注意:脚本会 DROP 并重建所有表,不会保留历史数据。 ### 2. 启动后端 修改 `backend/src/main/resources/application.yml` 中的数据库连接信息(用户名/密码),然后: ```bash cd backend mvn spring-boot:run ``` 后端默认运行在 `http://localhost:8080`。 ### 3. 启动前端 ```bash cd frontend npm install npm run dev ``` 前端默认运行在 `http://localhost:5173`,已配置代理将 `/api` 转发到后端 `8080` 端口。 ## 初始账号 | 工号 | 用户名 | 角色 | 密码 | | --- | --- | --- | --- | | 000001 | 超级管理员01 | 超级管理员 | user@000001 | > 另含两个测试账号: > - 管理员:工号 `100001`,密码 `admin@100001` > - 普通用户:工号 `200001`,密码 `user@200001` ## Token 机制说明 ### 双 Token 设计 | Token | 有效期 | 用途 | | --- | --- | --- | | Access Token | 2 小时 | 用于 API 请求认证 | | Refresh Token | 4 小时 | 用于刷新 Access Token | 两个 Token 均存储在 Cookie 中(`HttpOnly` 保护),前端通过 `withCredentials: true` 自动携带。 ### 刷新流程 ``` 1. 前端发起 API 请求,自动从 Cookie 携带 Access Token 2. 后端校验 Access Token,若过期则返回 401 3. 前端拦截到 401,自动调用 /api/auth/refresh 刷新接口(携带 Refresh Token) 4. 刷新成功后,后端更新 Cookie 中的 Access Token 与 Refresh Token 5. 前端重放原请求,用户无感知 6. 若 Refresh Token 也已过期,则跳转登录页重新登录 ``` ## 双认证方式说明 需要认证的接口支持两种调用方式,兼容不同调用场景: ### 1. JWT Token(页面调用场景) 前端浏览器通过 Cookie 自动携带 Access Token,适用于页面交互调用。 ### 2. Basic Auth(服务调用场景) 适用于服务间调用(无浏览器 Cookie 环境),在请求头携带: ``` Authorization: Basic base64(userNo:password) ``` 例如工号 `000001`、密码 `user@000001`: ```bash curl -u 000001:user@000001 http://localhost:8080/api/app/list?current=1&size=10 # 等价于 curl -H "Authorization: Basic MDAwMDAxOnVzZXJAMDAwMDAx" http://localhost:8080/api/app/list?current=1&size=10 ``` ### 3. 注解式免认证白名单 在 Controller 方法或类上标注 `@NoAuth` 注解,即可声明该接口无需认证鉴权: ```java // 方法级 @NoAuth @PostMapping("/login") public Result login(...) { ... } // 类级(整个 Controller 免认证) @NoAuth @RestController public class PublicController { ... } ``` > 登录(`/api/auth/login`)、退出(`/api/auth/logout`)、刷新(`/api/auth/refresh`)三个接口均已标注 `@NoAuth`。 ## 修改密码与密码强度 登录用户可通过右上角用户菜单的「修改密码」功能修改自己的密码。 **密码强度规则**(前后端双重校验,规则一致): 1. 长度不少于 8 位; 2. 仅由英文、数字及 `@#&*-_$` 等特殊符号组成; 3. 至少包含英文、数字、特殊符号中的其中两种。 修改密码时需输入旧密码进行校验,修改成功后自动退出登录,需重新登录。 ## 应用操作权限控制 应用编辑、删除操作遵循以下权限规则: | 角色 | 权限 | | --- | --- | | 超级管理员(SUPER_ADMIN) | 可编辑、删除所有应用 | | 管理员(ADMIN) | 可编辑、删除所有应用 | | 普通用户(USER) | 仅能编辑、删除自己是管理员A 或管理员B 的应用 | 前端根据权限禁用按钮,后端在接口层做最终校验(防止绕过前端直接调用接口)。 此外,创建应用时管理员A 为必填项且默认当前登录用户;编辑应用时应用英文名不可修改。 ## 动态菜单权限说明 系统通过 `sys_role_menu` 表配置不同角色可访问的前端页面。 - **超级管理员(SUPER_ADMIN)** 与 **管理员(ADMIN)**:拥有全部页面权限。 - **普通用户(USER)**:按 `sys_role_menu` 表配置,默认仅可访问「应用管理」页面。 登录后,前端调用 `/api/menu/mine` 获取当前用户可访问的菜单列表,据此动态渲染左侧菜单,并在路由守卫中拦截无权限的页面访问(跳转 403 页面)。 新增页面时,在 `sys_role_menu` 表中补充对应角色的 `menu_path` 配置,并在前端路由中增加对应页面即可。 ## 主要 API ### 认证接口 | 方法 | 路径 | 说明 | 认证 | | --- | --- | --- | --- | | POST | /api/auth/login | 登录(body: `{ userNo, password }`) | @NoAuth | | POST | /api/auth/logout | 退出登录 | @NoAuth | | POST | /api/auth/refresh | 刷新 Token | @NoAuth | | POST | /api/auth/change-password | 修改密码(body: `{ oldPassword, newPassword }`) | 需认证 | ### 菜单权限接口 | 方法 | 路径 | 说明 | | --- | --- | --- | | GET | /api/menu/mine | 当前用户可访问的菜单列表 | ### 用户管理接口 | 方法 | 路径 | 说明 | | --- | --- | --- | | GET | /api/user/list | 用户列表(可选 `keyword`) | | GET | /api/user/options | 用户下拉选项(用于应用管理员选择,可选 `keyword`) | | GET | /api/user/{id} | 用户详情 | | POST | /api/user | 新增用户 | | PUT | /api/user | 修改用户 | | DELETE | /api/user/{id} | 删除用户 | ### 应用管理接口 | 方法 | 路径 | 说明 | | --- | --- | --- | | GET | /api/app/list | 应用列表(后端分页:`current`/`size`/`keyword`) | | GET | /api/app/{id} | 应用详情 | | POST | /api/app | 新增应用 | | PUT | /api/app | 修改应用 | | DELETE | /api/app/{id} | 删除应用 | ### 操作审计接口 | 方法 | 路径 | 说明 | | --- | --- | --- | | GET | /api/audit/list | 操作日志分页查询(`current`/`size`/`keyword`) | ## 数据库表说明 | 表名 | 说明 | | --- | --- | | sys_user | 用户表(工号、用户名、密码 MD5、角色) | | sys_app | 应用表(英文名、中文名、管理员A/B、技术栈) | | sys_operation_log | 操作日志表(工号、姓名、操作类型、时间、请求参数) | | sys_role_menu | 角色-菜单权限表(角色、页面路由、页面名称、排序) | ## 日志说明 后端通过 logback 记录日志,配置文件为 `backend/src/main/resources/logback-spring.xml`。 - **控制台输出**:开发调试用 - **文件输出**:`logs/app-manage.log`(相对后端运行目录),按天滚动,保留最近 30 天,单文件超过 10MB 自动切割 关键业务节点均记录日志(不打印明文密码),便于故障排查: - 登录成功/失败、登出、Token 刷新、修改密码 - 应用、用户的新增/修改/删除 - 认证通过/失败(JWT / Basic Auth) - 业务异常、未授权、系统异常(含完整堆栈) - MyBatis SQL 语句与参数(DEBUG 级别) ## 注意事项 - 密码采用 **MD5** 加密存储(演示用途,生产环境建议使用 BCrypt)。 - JWT 密钥配置在 `application.yml` 的 `jwt.secret`,生产环境务必替换为随机强密钥。 - Basic Auth 使用与登录相同的账号体系(`sys_user` 表的工号 + 密码)。 - 逻辑删除使用 MyBatis-Plus 的 `@TableLogic` 注解。 - 角色编码:`SUPER_ADMIN`(超级管理员)、`ADMIN`(管理员)、`USER`(普通用户)。 - 超级管理员账号不允许被删除。 - 前端登录用户信息缓存在 `localStorage` 的 `app_manage_user` 键下,退出登录时自动清除。 - 密码强度规则同时在前端(表单校验)与后端(接口校验)实现,修改密码时需满足:长度 ≥ 8 位、仅英文/数字/`@#&*-_$` 特殊符号、至少包含其中两类。