# 统一登录网关平台 ## 一、项目概述 ### 1.1 项目背景 当前存在多个独立业务系统,各系统均有独立的登录模块、用户体系和权限管理,导致用户需要记忆多套账号密码,管理员需要在多个系统中重复维护用户信息,权限管理混乱且难以统一管控。 ### 1.2 项目目标 构建一个统一的多系统登录与权限网关平台,实现: - 统一登录入口:所有业务系统共用一个登录页面(https://login.user.mokee.com),用户一次登录即可访问所有授权系统 - 统一用户管理:所有用户信息集中在网关平台维护,业务系统不再存储用户数据 - 统一权限管理:所有业务系统的菜单、角色、权限集中在网关平台配置 - 统一接口转发:所有业务系统的接口请求统一经过网关转发,网关负责身份认证和用户信息透传 - 可配置化接入:新增业务系统无需修改网关代码,仅需在后台配置系统信息即可快速接入 - 智能系统跳转:登录成功后自动判断用户绑定系统数量,多系统展示选择页,单系统直接跳转 ### 1.3 核心价值 - 提升用户体验:用户无需记忆多套账号密码,一次登录即可访问所有授权系统 - 降低管理成本:管理员只需在一个平台维护用户和权限信息 - 提高系统安全性:统一身份认证和接口鉴权,避免非法访问 - 便于系统扩展:新增业务系统可快速接入,无需重复开发登录和权限模块 --- ## 二、技术架构 ### 2.1 整体架构图 ``` [用户浏览器] ↓ [业务系统前端] → [统一登录页面(https://login.user.zgitm.com)] ↓ [网关服务(9000)] → [认证用户服务(9001)] ↓ ↓ [业务系统后端] ← [业务管理服务(9002)] ↓ [MySQL数据库] ← [Redis缓存] ``` ### 2.2 微服务拆分与职责 #### 2.2.1 网关服务(mokee-gateway-gateway)- 端口9000 - 统一入口:所有业务系统的接口请求和页面访问统一经过网关 - 路由转发:根据配置的系统信息,将请求转发到对应的业务系统后端 - 身份认证:校验请求中的Token有效性,拦截未登录请求 - 信息透传:将用户ID、用户名、角色、岗位、系统ID等信息注入请求头,传递给业务系统后端 - 接口鉴权:校验请求接口是否在业务系统的放行列表中 #### 2.2.2 认证用户服务(mokee-gateway-auth)- 端口9001 - 登录认证:处理用户登录请求,验证账号密码,生成Token - 用户管理:维护用户基本信息、用户与系统的绑定关系 - 权限管理:维护角色、菜单信息,用户与角色的绑定关系 - 会话管理:管理Redis中的用户登录会话,处理退出登录请求 - 基础接口:提供获取用户信息、系统信息、菜单路由等基础接口 - 系统选择:登录成功后判断用户绑定系统数量,返回系统列表或直接跳转 #### 2.2.3 业务管理服务(mokee-gateway-admin)- 端口9002 - 系统管理:维护业务系统的基本信息、域名配置、接口放行列表 - 数据字典:维护全局通用的数据字典 - 日志管理:记录用户登录日志和系统操作日志 - 定时任务:执行系统定时任务,如自动锁定长期未登录用户 ### 2.3 技术栈明细 | 技术领域 | 技术选型 | 版本要求 | |---------|---------|---------| | 后端框架 | Spring Boot | 3.0+ | | 开发语言 | Java | 17.0.12+ | | 前端框架 | Vue3 | 最新稳定版 | | 数据库 | MySQL | 8.0+ | | 缓存 | Redis | 最新稳定版 | | 服务通信 | OpenFeign | Spring Boot 3配套版本 | | 日志 | SLF4J + Logback | Spring Boot 3配套版本 | | 部署 | Kubernetes | 用户自行部署 | ### 2.4 环境配置 #### 2.4.1 数据库配置 ```yaml spring: datasource: url: jdbc:mysql://db1.prod.zgitm.com:3306/mokeegateway?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: mokeegateway password: mokee. driver-class-name: com.mysql.cj.jdbc.Driver ``` #### 2.4.2 Redis配置 ```yaml spring: redis: host: redis.db1.zgitm.com port: 6379 database: 1 password: mokee2016. timeout: 3000ms ``` #### 2.4.3 开发环境配置 - JDK路径:E:\javaJdk\jdk-17.0.12 - Maven路径:E:\apache-maven-3.6.0 - 统一登录平台本地开发地址:http://127.0.0.1:3300 - 统一登录平台生产域名:https://login.user.zgitm.com --- ## 三、核心功能实现 ### 3.1 统一登录功能(新增系统选择页) #### 3.1.1 登录流程(修订版) 1. 用户访问任意业务系统前端域名 2. 业务系统前端检测本地无有效Token,自动跳转至统一登录页面:https://login.user.mokee.com 3. 跳转时携带回调参数:redirect=当前业务系统完整地址(可选,若用户直接访问登录页则无此参数) 4. 用户在统一登录页面输入账号/邮箱+密码 5. 认证用户服务验证账号密码,验证通过后生成Token 6. 将Token和用户信息存入Redis,设置过期时间 7. 系统选择逻辑: - 查询当前用户绑定的所有启用状态的业务系统 - 若用户只绑定了1个系统:自动跳转至该系统的前端地址 - 若用户绑定了多个系统:跳转至网关平台的系统选择页面,展示所有可访问系统列表 - 用户点击选择目标系统后,跳转至对应系统的前端地址 8. 业务系统前端将Token存入本地存储 #### 3.1.2 系统选择页面功能 - 展示用户所有可访问的业务系统卡片(包含系统名称、系统图标、系统描述) - 点击系统卡片自动跳转至对应系统的前端地址 - 支持退出登录功能,跳转回统一登录页 - 页面适配PC端和移动端 #### 3.1.3 登录成功返回信息 ```json { "code": 200, "msg": "登录成功", "data": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "userInfo": { "userId": "123e4567-e89b-12d3-a456-426614174000", "username": "张三", "email": "zhangsan@example.com", "phone": "13800138000", "avatar": "https://example.com/avatar.jpg", "post": "产品经理" }, "systemList": [ { "systemId": "456e4567-e89b-12d3-a456-426614174001", "systemCode": "msg", "systemName": "信息管理系统", "frontUrl": "https://web.msg.mokee.com" }, { "systemId": "789e4567-e89b-12d3-a456-426614174002", "systemCode": "oa", "systemName": "办公自动化系统", "frontUrl": "https://web.oa.mokee.com" } ], "needSelectSystem": true }, "timestamp": 1718000000000 } ``` ### 3.2 系统配置功能 #### 3.2.1 系统信息配置 每个业务系统需要配置以下信息: - 系统编码:唯一标识业务系统的字符串(如:msg、oa、finance) - 系统名称:业务系统的中文名称(如:信息管理系统、办公自动化系统) - 系统前端地址:业务系统前端的访问域名(如:https://web.msg.mokee.com) - 系统后端地址:业务系统后端的真实服务地址(如:https://server.msg.mokee.com) - 网关API域名:业务系统专用的 API 域名,DNS 指向网关服务器(如:https://or.test.mokee.com),网关通过域名自动识别业务系统 - 系统图标:系统选择页面展示的图标 - 系统状态:启用/禁用 - 系统描述:业务系统的简要说明 #### 3.2.2 接口放行配置 每个业务系统需要配置允许访问的接口列表: - 接口路径:接口的请求路径(如:/zgapi/v1/user/list) - 请求方式:GET/POST/PUT/DELETE - 接口名称:接口的中文名称 - 接口状态:启用/禁用 ### 3.3 接口转发功能 #### 3.3.1 转发流程 1. 业务系统前端使用独立的 API 域名(DNS 指向网关),携带 Token 发起接口请求 2. 网关服务从请求头中获取Token,校验Token有效性 3. 从Redis中获取用户信息和当前系统信息 4. 根据请求的 Host 头域名,匹配对应业务系统的 gateway_url,自动识别业务系统 5. 校验请求接口是否在该业务系统的放行列表中 6. 注入请求头信息:将用户ID、用户名、角色、岗位、系统ID等信息注入请求头 7. 将请求转发到业务系统的真实后端地址 8. 将业务系统后端的响应返回给前端 #### 3.3.2 请求头注入信息(完整) 网关服务在转发请求时,会在请求头中注入以下信息,业务系统后端直接从请求头获取即可: | 请求头字段 | 说明 | |-----------|------| | X-User-Id | 当前登录用户的唯一ID(UUID) | | X-User-Name | 当前登录用户的真实姓名 | | X-User-Account | 当前登录用户的登录账号 | | X-User-Email | 当前登录用户的邮箱 | | X-User-Post | 当前登录用户的岗位 | | X-User-Roles | 当前用户在该系统下的角色列表(JSON数组字符串) | | X-System-Id | 当前访问的业务系统ID | | X-System-Code | 当前访问的业务系统编码 | | X-System-Name | 当前访问的业务系统名称 | #### 3.3.3 业务系统后端处理 业务系统后端无需实现任何登录和权限逻辑,只需从请求头中获取上述用户和系统信息,进行业务处理和数据隔离即可。 ### 3.4 菜单与权限管理 #### 3.4.1 菜单配置 每个业务系统的菜单在网关平台配置,包括: - 菜单名称 - 菜单路径 - 前端组件路径 - 菜单图标 - 菜单类型(目录/菜单/按钮) - 排序 - 状态 #### 3.4.2 角色管理 每个业务系统可以创建多个角色,角色与菜单绑定: - 角色名称 - 角色编码 - 角色描述 - 绑定的菜单列表 #### 3.4.3 用户授权 用户与业务系统绑定,在每个业务系统下可以分配一个或多个角色: - 用户绑定业务系统 - 在业务系统下为用户分配角色 - 用户的权限为所分配角色的权限合并 #### 3.4.4 动态路由生成 业务系统前端登录成功后,向网关请求当前用户在该系统下的菜单路由: 1. 前端携带Token请求菜单接口(网关通过域名自动识别系统) 2. 认证用户服务查询用户在该系统下的所有角色 3. 合并所有角色的菜单权限 4. 生成Vue动态路由JSON返回给前端 5. 前端根据路由JSON动态生成路由并渲染页面 ### 3.5 日志管理 #### 3.5.1 登录日志 记录所有用户的登录信息,包括: - 用户ID - 用户名 - 登录时间 - 登录IP - 登录系统 - 登录状态(成功/失败) - 浏览器信息 - 操作系统信息 #### 3.5.2 操作日志 通过AOP切面自动记录所有用户的操作信息,包括: - 操作人ID - 操作人名称 - 操作时间 - 操作模块 - 操作类型(新增/编辑/删除/查询) - 请求地址 - 请求方式 - 请求参数 - 响应结果 - 操作状态(成功/失败) ### 3.6 定时任务 系统内置定时任务: - 自动锁定长期未登录用户:每日扫描用户登录日志,自动锁定连续1年未登录的用户账号 - 清理过期日志:定期清理超过保留期限的登录日志和操作日志 --- ## 四、数据库设计 ### 4.1 核心数据表 #### 4.1.1 系统表(sys_system) | 字段名 | 数据类型 | 主键 | 说明 | |-------|---------|------|------| | system_id | varchar(36) | 是 | 系统ID(UUID) | | system_code | varchar(64) | 否 | 系统编码(唯一) | | system_name | varchar(128) | 否 | 系统名称 | | front_url | varchar(256) | 否 | 系统前端地址 | | backend_url | varchar(256) | 否 | 系统后端真实地址 | | gateway_url | varchar(256) | 否 | 网关代理地址(唯一) | | icon | varchar(256) | 否 | 系统图标地址 | | status | tinyint | 否 | 系统状态(0-禁用,1-启用) | | description | text | 否 | 系统描述 | | create_time | datetime | 否 | 创建时间 | | update_time | datetime | 否 | 更新时间 | #### 4.1.2 系统接口表(sys_system_api) | 字段名 | 数据类型 | 主键 | 说明 | |-------|---------|------|------| | api_id | varchar(36) | 是 | 接口ID(UUID) | | system_id | varchar(36) | 否 | 关联系统ID | | api_path | varchar(256) | 否 | 接口路径 | | api_method | varchar(16) | 否 | 请求方式 | | api_name | varchar(128) | 否 | 接口名称 | | status | tinyint | 否 | 接口状态(0-禁用,1-启用) | | create_time | datetime | 否 | 创建时间 | | update_time | datetime | 否 | 更新时间 | #### 4.1.3 用户表(sys_user) | 字段名 | 数据类型 | 主键 | 说明 | |-------|---------|------|------| | user_id | varchar(36) | 是 | 用户ID(UUID) | | username | varchar(64) | 否 | 登录账号(唯一) | | password | varchar(128) | 否 | 加密密码 | | email | varchar(64) | 否 | 邮箱(唯一) | | phone | varchar(32) | 否 | 手机号 | | real_name | varchar(64) | 否 | 真实姓名 | | avatar | varchar(256) | 否 | 头像地址 | | post | varchar(64) | 否 | 岗位 | | status | tinyint | 否 | 用户状态(0-禁用,1-正常) | | last_login_time | datetime | 否 | 最后登录时间 | | create_time | datetime | 否 | 创建时间 | | update_time | datetime | 否 | 更新时间 | #### 4.1.4 用户系统关联表(sys_user_system) | 字段名 | 数据类型 | 主键 | 说明 | |-------|---------|------|------| | id | varchar(36) | 是 | 关联ID(UUID) | | user_id | varchar(36) | 否 | 用户ID | | system_id | varchar(36) | 否 | 系统ID | | create_time | datetime | 否 | 绑定时间 | #### 4.1.5 角色表(sys_role) | 字段名 | 数据类型 | 主键 | 说明 | |-------|---------|------|------| | role_id | varchar(36) | 是 | 角色ID(UUID) | | system_id | varchar(36) | 否 | 关联系统ID | | role_name | varchar(64) | 否 | 角色名称 | | role_code | varchar(64) | 否 | 角色编码 | | description | text | 否 | 角色描述 | | status | tinyint | 否 | 角色状态(0-禁用,1-启用) | | create_time | datetime | 否 | 创建时间 | | update_time | datetime | 否 | 更新时间 | #### 4.1.6 用户角色关联表(sys_user_role) | 字段名 | 数据类型 | 主键 | 说明 | |-------|---------|------|------| | id | varchar(36) | 是 | 关联ID(UUID) | | user_id | varchar(36) | 否 | 用户ID | | system_id | varchar(36) | 否 | 系统ID | | role_id | varchar(36) | 否 | 角色ID | | create_time | datetime | 否 | 绑定时间 | #### 4.1.7 菜单表(sys_menu) | 字段名 | 数据类型 | 主键 | 说明 | |-------|---------|------|------| | menu_id | varchar(36) | 是 | 菜单ID(UUID) | | system_id | varchar(36) | 否 | 关联系统ID | | parent_id | varchar(36) | 否 | 父菜单ID | | menu_name | varchar(64) | 否 | 菜单名称 | | menu_path | varchar(256) | 否 | 菜单路径 | | component | varchar(256) | 否 | 前端组件路径 | | icon | varchar(128) | 否 | 菜单图标 | | menu_type | tinyint | 否 | 菜单类型(1-目录,2-菜单,3-按钮) | | permission | varchar(128) | 否 | 权限标识 | | sort | int | 否 | 排序 | | status | tinyint | 否 | 菜单状态(0-禁用,1-启用) | | create_time | datetime | 否 | 创建时间 | | update_time | datetime | 否 | 更新时间 | #### 4.1.8 角色菜单关联表(sys_role_menu) | 字段名 | 数据类型 | 主键 | 说明 | |-------|---------|------|------| | id | varchar(36) | 是 | 关联ID(UUID) | | role_id | varchar(36) | 否 | 角色ID | | menu_id | varchar(36) | 否 | 菜单ID | #### 4.1.9 登录日志表(sys_login_log) | 字段名 | 数据类型 | 主键 | 说明 | |-------|---------|------|------| | log_id | varchar(36) | 是 | 日志ID(UUID) | | user_id | varchar(36) | 否 | 用户ID | | username | varchar(64) | 否 | 登录账号 | | system_id | varchar(36) | 否 | 登录系统ID | | login_ip | varchar(64) | 否 | 登录IP | | login_time | datetime | 否 | 登录时间 | | status | tinyint | 否 | 登录状态(0-失败,1-成功) | | browser | varchar(64) | 否 | 浏览器信息 | | os | varchar(64) | 否 | 操作系统信息 | #### 4.1.10 操作日志表(sys_operation_log) | 字段名 | 数据类型 | 主键 | 说明 | |-------|---------|------|------| | log_id | varchar(36) | 是 | 日志ID(UUID) | | user_id | varchar(36) | 否 | 操作人ID | | username | varchar(64) | 否 | 操作人名称 | | system_id | varchar(36) | 否 | 操作系统ID | | module | varchar(64) | 否 | 操作模块 | | operation | varchar(32) | 否 | 操作类型 | | request_url | varchar(256) | 否 | 请求地址 | | request_method | varchar(16) | 否 | 请求方式 | | request_param | text | 否 | 请求参数 | | response_result | text | 否 | 响应结果 | | status | tinyint | 否 | 操作状态(0-失败,1-成功) | | operation_time | datetime | 否 | 操作时间 | --- ## 五、接口规范 ### 5.1 统一返回格式 所有接口统一返回以下格式: ```json { "code": 200, "msg": "操作成功", "data": {}, "timestamp": 1718000000000 } ``` - code:响应状态码,200表示成功,其他表示失败 - msg:响应消息 - data:响应数据 - timestamp:响应时间戳 ### 5.2 主要接口列表 #### 5.2.1 认证接口 | 接口地址 | 请求方式 | 接口描述 | |---------|---------|---------| | /zgapi/v1/auth/login | POST | 用户登录 | | /zgapi/v1/auth/logout | POST | 退出登录 | | /zgapi/v1/auth/user/info | GET | 获取当前用户信息 | | /zgapi/v1/auth/menu/router | GET | 获取当前用户菜单路由 | | /zgapi/v1/auth/password/update | PUT | 修改密码 | | /zgapi/v1/auth/system/list | GET | 获取当前用户可访问系统列表 | --- ## 六、外部系统对接网关平台申请说明文档 > 注:在系统管理列表中,新增文档列,点击可以查看系统对接文档的超链接,这个是不要认证直接访问的。 ### 6.1 对接前提 1. 已在网关平台后台完成业务系统信息配置(系统编码、前端地址、后端地址、网关API域名) 2. 业务系统的 API 域名 DNS 已指向网关服务器,网关通过域名自动识别业务系统 3. 已在网关平台后台配置业务系统需要放行的接口列表 4. 已在网关平台后台为用户分配该业务系统的访问权限和角色 ### 6.2 前端系统修改步骤 #### 6.2.1 移除原有登录功能 - 删除业务系统原有的登录页面、登录接口、登录逻辑 - 删除业务系统原有的本地用户存储、Token管理逻辑 #### 6.2.2 配置全局路由守卫(核心) 在业务系统的router/index.ts中添加全局路由守卫,实现未登录自动跳转统一登录页: ```typescript import { createRouter, createWebHistory } from 'vue-router' import { useUserStore } from '@/stores/user' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ // 业务系统原有路由(无需保留登录路由) ] }) // 全局路由守卫 router.beforeEach((to, from, next) => { const userStore = useUserStore() const token = localStorage.getItem('token') // 统一登录平台地址 const LOGIN_URL = 'https://login.mokeeuserlogin.com' // 当前业务系统编码(从网关平台获取,用于登录回调参数) const SYSTEM_CODE = 'msg' if (!token) { // 未登录,跳转到统一登录页,携带当前页面地址作为回调 window.location.href = `${LOGIN_URL}?redirect=${encodeURIComponent(window.location.href)}&systemCode=${SYSTEM_CODE}` return } // 已登录,继续访问 next() }) export default router ``` #### 6.2.3 配置全局请求拦截器 在业务系统的utils/request.ts中配置全局请求拦截器,统一携带Token。 > **重要说明**:业务系统使用独立的 API 域名(如 `https://or.test.mokee.com`),DNS 指向网关服务器。网关通过请求的 Host 头域名自动识别业务系统,前端无需再发送 `X-System-Code` 请求头。 ```typescript import axios from 'axios' const service = axios.create({ // 业务系统独立的 API 域名(DNS 指向网关,从网关平台获取) baseURL: 'https://or.test.mokee.com', timeout: 30000 }) // 请求拦截器 service.interceptors.request.use( (config) => { const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }, (error) => { return Promise.reject(error) } ) // 响应拦截器 service.interceptors.response.use( (response) => { return response.data }, (error) => { // 401未授权,跳转到统一登录页 if (error.response && error.response.status === 401) { localStorage.removeItem('token') window.location.href = 'https://login.mokeeuserlogin.com' } return Promise.reject(error) } ) export default service ``` #### 6.2.4 实现动态路由加载 在业务系统的main.ts中添加动态路由加载逻辑: ```typescript import { createApp } from 'vue' import App from './App.vue' import router from './router' import { useUserStore } from './stores/user' const app = createApp(App) // 初始化时加载动态路由 const initApp = async () => { const userStore = useUserStore() const token = localStorage.getItem('token') if (token) { try { // 从网关获取当前用户在该系统下的菜单路由 const res = await userStore.getMenuRouter() // 动态添加路由 res.data.forEach((route) => { router.addRoute(route) }) } catch (error) { console.error('加载动态路由失败', error) localStorage.removeItem('token') window.location.href = 'https://login.mokeeuserlogin.com' } } app.use(router) app.mount('#app') } initApp() ``` #### 6.2.5 获取用户信息 在业务系统的stores/user.ts中实现获取用户信息和菜单路由的方法: ```typescript import { defineStore } from 'pinia' import request from '@/utils/request' export const useUserStore = defineStore('user', { state: () => ({ userInfo: null, menuList: [] }), actions: { // 获取当前用户信息 async getUserInfo() { const res = await request.get('/api/v1/auth/user/info') this.userInfo = res.data return res.data }, // 获取当前用户菜单路由 async getMenuRouter() { const res = await request.get('/api/v1/auth/menu/router', { params: { systemCode: 'msg' } }) this.menuList = res.data return res.data } } }) ``` ### 6.3 后端系统修改步骤 #### 6.3.1 移除原有登录和权限逻辑 - 删除业务系统原有的登录接口、用户表、角色表、权限表 - 删除业务系统原有的Token校验、权限拦截逻辑 #### 6.3.2 从请求头获取用户信息(核心) 业务系统后端无需访问网关,所有用户和系统信息都从网关注入的请求头中获取。以下是Java示例: ```java import jakarta.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/v1/user") public class UserController { @GetMapping("/current") public UserInfo getCurrentUser(HttpServletRequest request) { // 从请求头获取用户信息 String userId = request.getHeader("X-User-Id"); String userName = request.getHeader("X-User-Name"); String userAccount = request.getHeader("X-User-Account"); String userEmail = request.getHeader("X-User-Email"); String userPost = request.getHeader("X-User-Post"); String userRoles = request.getHeader("X-User-Roles"); String systemId = request.getHeader("X-System-Id"); String systemCode = request.getHeader("X-System-Code"); // 构建用户信息对象 UserInfo userInfo = new UserInfo(); userInfo.setUserId(userId); userInfo.setUserName(userName); userInfo.setUserAccount(userAccount); userInfo.setUserEmail(userEmail); userInfo.setUserPost(userPost); // 解析角色列表 userInfo.setRoles(JSON.parseArray(userRoles, String.class)); userInfo.setSystemId(systemId); userInfo.setSystemCode(systemCode); return userInfo; } } ``` #### 6.3.3 实现数据隔离 根据请求头中的用户ID和系统ID,实现业务数据的隔离: ```java @GetMapping("/list") public List getBusinessData(HttpServletRequest request) { String userId = request.getHeader("X-User-Id"); String systemId = request.getHeader("X-System-Id"); // 根据用户ID和系统ID查询该用户在该系统下的业务数据 return businessDataService.listByUserIdAndSystemId(userId, systemId); } ``` ### 6.4 对接测试步骤 1. 启动网关平台和业务系统 2. 访问业务系统前端地址,验证是否自动跳转到统一登录页 3. 使用测试账号登录,验证是否正确跳转到系统选择页或直接进入业务系统 4. 验证业务系统是否能正确获取用户信息和菜单路由 5. 验证业务系统接口请求是否经过网关转发,后端是否能正确获取请求头中的用户信息 6. 验证未授权接口是否被网关拦截 7. 验证退出登录功能是否正常 ### 6.5 常见问题 1. 跨域问题:请在网关服务中配置跨域支持,允许业务系统前端域名访问 2. Token过期:请在前端响应拦截器中处理401状态码,自动跳转到统一登录页 3. 请求头丢失:请确保网关服务在转发请求时正确保留和注入请求头 4. 动态路由加载失败:请检查网关平台是否正确配置了该系统的菜单和用户权限 --- ## 附录:文档审查问题清单 ### 🔴 严重不一致(必须修正) **#1 统一登录域名不一致** - 第 3.1.1 节:`https://login.user.mokee.com` - 第 6.2.2 节及后续多处:`https://login.mokeeuserlogin.com` - 建议统一为:`https://login.user.mokee.com` **#2 API 路径前缀不一致** - 第 5.2.1 节接口列表使用:`/zgapi/v1/auth/...` - 第 6.2.5 节前端示例代码使用:`/api/v1/auth/...`(缺少 `zg` 前缀) - 建议统一为:`/zgapi/v1/...` **#3 登录返回数据中的待确认项** - 第 3.1.3 节返回 JSON 注释:`//还要不要加一个当前选着系统?`("选着"是错别字,应为"选择") - 需确认:是否需要返回"当前选中系统"信息? ### 🟡 数据表设计问题(建议修正) **#4 sys_user_role 表冗余字段** - `sys_user_role` 表有 `system_id` 字段,但 `role_id` 关联的 `sys_role` 表已包含 `system_id` —— 不一致风险 **#5 缺少逻辑删除字段** - 所有表无 `is_deleted` 字段 **#6 缺少审计字段** - 所有表缺少 `created_by` / `updated_by` **#7 sys_role_menu 表缺少时间字段** - 与其他关联表(`sys_user_system`、`sys_user_role`)不一致 **#8 sys_user 表缺少字段** - 缺少 `last_login_ip` - 密码加密算法未明确(BCrypt?SCrypt?) **#9 未定义索引策略** - 所有表未提及索引设计 ### 🟠 功能缺失(建议补充) **#10 缺少 Token 刷新机制** **#11 缺少统一登出(SSO Logout)** **#12 缺少登录安全措施** - 无验证码机制 - 无密码复杂度策略 - 无账号锁定策略(多次失败锁定) - 无限流机制 **#13 缺少跨域(CORS)配置方案** **#14 X-User-Roles 请求头格式未明确** - 数组元素包含哪些字段? ### 🔵 细节问题 **#15 needSelectSystem 字段冗余** - 前端可通过 `systemList.length > 1` 判断 **#16 前端代码示例问题** - 路由守卫缺 `async` - 每次路由切换都读 localStorage(性能) **#17 第 3 节与第 6 节内容重叠**