# 登录模块综合开发指南（LOGIN_COMPREHENSIVE_GUIDE）

版本：v1.1.0（2025-12-27）  
适用范围：Sys（后台管理端）、App（移动端）两套登录体系及微信公众号整合  
最后更新：2025-12-27

---

## 目录
1. 登录模块概述
2. 详细开发指南
3. 登录流程示意图
4. 实现方案
5. 模块规范
6. App 会话管理 API
7. Sys 在线用户管理 API
8. Sys 登录日志管理 API
9. 相关代码路径参考

---

## 1. 登录模块概述

- 背景与目的  
  - 系统同时支持 Sys 与 App 两套登录体系，分别面向管理员与 C 端用户，要求登录态、权限与数据完全隔离，同时提供统一的扩展与维护指引。  
  - 采用策略模式（Strategy Pattern）实现登录方式的可插拔扩展，基于 Sa-Token 管理会话与权限，支持验证码、限流、并发与设备维度会话。  
  - 集成微信公众号能力：App 用于授权登录与业务交互；Sys 用于管理员绑定与模板消息推送。

- 目标  
  - 统一规范开发流程与接口定义，保障多端、多方式登录的稳定性与可扩展性。  
  - 为新增登录方式与微信能力提供清晰的落地步骤与测试方案。

---

## 2. 详细开发指南

### 2.1 多用户体系与会话隔离
- 物理隔离 + 逻辑统一：`sys_user` 与 `app_user` 两套用户体系；统一使用 Sa-Token 管理会话。  
- LoginId 前缀隔离：  
  - Sys：`sys_user:{id}`  
  - App：`app:{id}`  
- 会话校验（Sys 全局拦截）：参考 SecurityConfig 的 `StpUtil.checkLogin()` 与路由校验，确保 Token 与 clientid 一致。

### 2.2 App 开发要点
- 策略模式登录：`IAppAuthStrategy` 以 `grantType` 路由到具体策略（密码、短信、社交、微信等）。  
- 验证码与密码重试：`captcha.enable=true` 可开关；错误次数与锁定时间通过配置项控制。  
- 信息补全向导（过滤器）：登录后若用户资料未完善，仅放行“查询个人信息/绑定手机号”接口，其余拦截返回 403。

### 2.3 Sys 开发要点
- 安全加固：  
  - 异地登录检测：比对最近一次登录 IP 归属地变化并告警（日志/邮件）。  
  - 强制改密策略：登录后检查密码更新时间是否超期，超期在 Session 写入标记，拦截除改密外所有接口。  
- 管理员微信绑定与消息推送：后台生成带参二维码，管理员扫码绑定 `openId/unionId`，用于模板消息推送。
  
（最小改动策略）  
- 保留现有 Sys 登录与权限实现，不做核心代码改造。  
- 新增或接入的仅为“管理员微信绑定二维码生成”“SCAN/SUBSCRIBE 回调绑定”“模板消息推送”三个能力点；其余增强（如异地登录与强制改密）可按需增量加入，不影响主流程。

### 2.4 微信公众号整合（双端）
- App：OAuth2 获取 `openId/unionId`，优先 `unionId` 进行跨应用账号识别；若未绑定则返回 401 并引导绑定手机号。  
- Sys：生成 `scene_str=sys_user:{userId}` 的二维码，接收 `SCAN/SUBSCRIBE` 事件解析并绑定，后续通过模板消息进行系统通知与订单推送。

---

## 3. 登录流程示意图

### 3.1 App 登录总体流程
```mermaid
sequenceDiagram
  participant Client as 客户端
  participant Controller as AppAuthController
  participant Strategy as IAppAuthStrategy
  participant Service as AppLoginService
  participant Redis as Redis
  Client->>Controller: POST /app/auth/login
  Controller->>Strategy: authenticate(body, client, grantType)
  Strategy->>Service: checkLogin(...)
  Service->>Redis: PWD_ERR_CNT_KEY
  Strategy->>Controller: LoginVo(token, expire)
  Controller-->>Client: 返回结果
```

### 3.2 App 微信公众号授权登录
```mermaid
sequenceDiagram
  participant H5 as 前端网页
  participant Wx as 微信OAuth2
  participant AppAPI as AppAuthController
  participant MP as WxMpService
  H5->>Wx: 跳转授权，获取code
  H5->>AppAPI: grantType=wechat_mp, code
  AppAPI->>MP: getAccessToken(code)
  MP-->>AppAPI: openId, accessToken
  AppAPI->>MP: userInfo(openId)
  MP-->>AppAPI: unionId
  AppAPI->>DB: 查询app_social_auth by unionId
  alt 已绑定
    AppAPI-->>H5: 登录成功
  else 未绑定
    AppAPI-->>H5: 401_BIND_REQUIRED + tempKey
  end
```

### 3.3 Sys 管理员绑定与模板消息推送
```mermaid
flowchart LR
  A[管理员点击绑定] --> B[生成带参二维码 scene_str=sys_user:{userId}]
  B --> C[管理员扫码]
  C --> D[WxMpPortal接收SCAN/SUBSCRIBE]
  D --> E[解析EventKey与OpenId]
  E --> F[查询UnionId]
  F --> G[更新管理员绑定信息]
  G --> H[SysMessageService发送模板消息]
```

---

## 4. 实现方案

### 4.1 架构与技术选型
- Sa-Token：统一的会话与权限管理（Token 名称、并发、多设备）。  
- 策略模式：按 `grantType` 定位不同登录策略，低耦合、易扩展。  
- WxJava：`ruoyi-mp` 模块提供的公众号 OAuth2 与模板消息能力。  
- 线程池与并发：按需启用全局线程池或在 JDK21 使用虚拟线程。

### 4.2 关键实现细节
- LoginId 前缀实现：`LoginUser.getLoginId()` 返回 `userType + ":" + userId`。  
- App 密码策略：开启验证码校验时执行 `validateCaptcha()`；错误次数与锁定时间通过配置项 `user.password.maxRetryCount`、`user.password.lockTime` 控制。  
- App 信息补全：过滤器中检查 `infoComplete`，仅放行指定白名单接口（配置项 `user.auth.whitelist`），其余拦截返回 403。  
- App 微信授权：`getAccessToken(code) → userInfo(openId)`，优先使用 `unionId` 识别；未绑定返回 401 与临时 Key，引导绑定手机号。  
- Sys 管理员绑定：二维码 `scene_str=sys_user:{userId}`；接收事件后解析 `EventKey` 与 `OpenId`，查询 `unionId` 并写入绑定信息；后续根据 `openId` 推送模板消息。  
- 异地登录检测：在记录登录信息时调用 `LoginRiskService.checkRisk(userId, ip)`，比较归属地变化并告警。  
- 强制改密：登录后检查密码更新时间是否超期，标记 Session 并在拦截器中只放行改密接口。

### 4.4 配置项说明
- **验证码配置**（`application.yml`）：
  ```yaml
  captcha:
    enable: true              # 是否启用验证码校验
    type: MATH                # 验证码类型（MATH数学计算 / CHAR字符验证）
    category: CIRCLE          # 干扰类型（LINE线段 / CIRCLE圆圈 / SHEAR扭曲）
    numberLength: 1           # 数字验证码位数
    charLength: 4             # 字符验证码长度
  ```
- **用户密码策略配置**（`application.yml`）：
  ```yaml
  user:
    password:
      maxRetryCount: 5        # 密码最大错误次数
      lockTime: 10            # 密码锁定时间（分钟）
  ```
- **App端验证码与白名单配置**（`application.yml`）：
  ```yaml
  user:
    auth:
      captcha:
        enabled: false        # App端验证码开关
        type: math            # 验证码类型
      whitelist: /app/user/profile,/app/user/bind,/app/auth/logout  # 信息补全白名单
  ```
- **客户端配置**：在 `sys_client` 表中配置客户端信息，包括 `client_id`、`grant_type`（支持多个，逗号分隔）、`status`、`timeout`、`active_timeout` 等。

### 4.3 OAuth 与 MP 职责划分
- 第三方登录（OAuth）：使用 justauth
  - 属性来源：`application*.yml` 中的 `justauth.type.*`
  - 代码路径：属性绑定 [SocialProperties](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java)，工厂方法 [SocialUtils.getAuthRequest](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java#L35-L74)
  - 使用位置：App 端策略 [AppWechatMpAuthStrategy](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/service/impl/AppWechatMpAuthStrategy.java)、[AppWechatOpenAuthStrategy](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/service/impl/AppWechatOpenAuthStrategy.java)、[AppWechatMiniprogramAuthStrategy](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/service/impl/AppWechatMiniprogramAuthStrategy.java)
  - 说明：source 包含 `wechat_mp`、`wechat_open`、`wechat_miniprogram`、`github`、`gitee` 等，统一由 justauth 提供 OAuth 能力
- 公众号服务端能力（MP）：使用 `wx.*`
  - 属性来源：`application*.yml` 中的 `wx.mp.*`、`wx.miniapp.*`、`wx.pay.*`
  - 代码路径：属性绑定 [WxMpProperties](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-modules/ruoyi-mp/src/main/java/org/dromara/mp/config/WxMpProperties.java)，装配 [WxMpConfiguration](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-modules/ruoyi-mp/src/main/java/org/dromara/mp/config/WxMpConfiguration.java)
  - 使用位置：消息入口 [WxMpPortalController](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-modules/ruoyi-mp/src/main/java/org/dromara/mp/controller/WxMpPortalController.java)、二维码接口 [WxMpQrCodeController](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-modules/ruoyi-mp/src/main/java/org/dromara/mp/controller/WxMpQrCodeController.java)
  - 说明：MP 提供消息接收、二维码、模板消息推送等服务端功能，不用于 OAuth 登录
  
---

## 5. 模块规范

### 5.1 接口定义与参数

#### Sys 登录接口
- **路径**：`/auth/login`  
- **方法**：`POST`
- **支持的grantType**：
  - `password` - 密码登录（参数：`username`, `password`, 可选 `code/uuid`验证码）
  - `sms` - 短信登录（参数：`phonenumber`, `smsCode`）
  - `email` - 邮箱登录（参数：`email`, `emailCode`）
  - `social` - 第三方登录（参数：`source`, `socialCode`, `socialState`）
- **通用参数**：`clientId`（必填）
- **返回**：`LoginVo`（包含 `accessToken`, `expireIn`, `clientId`）
- **代码路径**：[AuthController.login](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/controller/AuthController.java#L75-L101)

#### Sys 退出登录接口
- **路径**：`/auth/logout`  
- **方法**：`POST`
- **权限**：需要登录态
- **说明**：退出当前登录会话，清除Token
- **代码路径**：[AuthController.logout](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/controller/AuthController.java#L164-L168)

#### Sys 用户注册接口
- **路径**：`/auth/register`  
- **方法**：`POST`
- **参数**：`username`, `password`, `userType`, 可选 `code/uuid`（验证码）
- **说明**：系统用户注册，需系统开启注册功能
- **代码路径**：[AuthController.register](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/controller/AuthController.java#L174-L181)

#### Sys 第三方绑定接口
- **获取绑定URL**：`GET /auth/binding/{source}?domain={domain}`
  - 生成第三方授权跳转URL，用于绑定第三方账号
- **回调绑定**：`POST /auth/social/callback`
  - 前端回调后绑定第三方账号（需token）
- **取消绑定**：`DELETE /auth/unlock/{socialId}`
  - 取消已绑定的第三方账号（需token）
- **代码路径**：[AuthController](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/controller/AuthController.java#L109-L158)

#### App 登录接口
- **路径**：`/app/auth/login`  
- **方法**：`POST`
- **支持的grantType**：
  - `app_password` - 密码登录（参数：`username`, `password`）
  - `sms` - 短信登录（参数：`phonenumber`, `smsCode`）
  - `email` - 邮箱登录（参数：`email`, `emailCode`）
  - `social` - 第三方登录（参数：`source`, `socialCode`, `socialState`）
  - `wechat_mp` - 微信公众号登录（参数：`socialCode`, `socialState`）
  - `wechat_open` - 微信开放平台登录（参数：`socialCode`, `socialState`）
  - `wechat_miniprogram` - 微信小程序登录（参数：`socialCode`, `socialState`）
- **通用参数**：`clientId`（必填）
- **返回**：`LoginVo`（包含 `accessToken`, `expireIn`, `clientId`）
- **代码路径**：[AppAuthController.login](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/controller/AppAuthController.java#L69-L93)

#### App 退出登录接口
- **路径**：`/app/auth/logout`  
- **方法**：`POST`
- **权限**：需要登录态
- **说明**：退出当前登录会话，清除Token
- **代码路径**：[AppAuthController.logout](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/controller/AppAuthController.java#L100-L104)

#### App 用户注册接口
- **路径**：`/app/auth/register`  
- **方法**：`POST`
- **参数**：`username`, `password`
- **限流**：60秒内最多1次（按IP）
- **说明**：App用户注册，需系统开启注册功能
- **代码路径**：[AppAuthController.register](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/controller/AppAuthController.java#L115-L132)

#### App 配置接口
- **路径**：`/app/auth/config`  
- **方法**：`GET`
- **说明**：获取App端配置信息（如注册开关等）
- **代码路径**：[AppAuthController.getConfig](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/controller/AppAuthController.java#L139-L145)

#### 验证码接口
- **图形验证码**：`GET /auth/code`
  - 返回：`CaptchaVo`（包含 `uuid`, `img`（Base64图片）, `captchaEnabled`）
  - 限流：60秒内最多10次（按IP）
  - **代码路径**：[CaptchaController.getCode](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/controller/CaptchaController.java#L112-L121)
- **短信验证码**：`GET /resource/sms/code?phonenumber={phonenumber}`
  - 限流：60秒内最多1次（按手机号）
  - **代码路径**：[CaptchaController.smsCode](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/controller/CaptchaController.java#L59-L76)
- **邮箱验证码**：`GET /resource/email/code?email={email}`
  - 限流：60秒内最多1次（按邮箱）
  - **代码路径**：[CaptchaController.emailCode](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/controller/CaptchaController.java#L83-L90)

#### 管理员绑定微信（建议）
- **生成绑定二维码**：`POST /wx/mp/qrcode/{appid}/forever?sceneStr=sys_user:{userId}`
  - 生成永久二维码，scene_str = sys_user:{userId}
- **获取二维码URL**：`GET /wx/mp/qrcode/{appid}/url?ticket={ticket}`
  - 根据ticket获取二维码图片URL
- **事件回调**：`WxMpPortalController` 处理 `SCAN/SUBSCRIBE` 事件并完成绑定
  - **代码路径**：[WxMpPortalController](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-modules/ruoyi-mp/src/main/java/org/dromara/mp/controller/WxMpPortalController.java)

### 5.2 会话与权限规范
- Token 名称：`Authorization`（统一）。  
- 并发策略：`is-concurrent=true` 支持多设备，按需要设置 `deviceType`。  
- 登录态隔离：Sys 与 App 使用不同 LoginId 前缀与独立会话空间。  
- 鉴权方式：Sys 采用注解鉴权（`@SaCheckPermission` 等）；App 采用资源级鉴权（业务层校验 `userId` 所属资源）。

### 5.3 错误码与处理
- `401_BIND_REQUIRED`：微信授权成功但未绑定手机号，引导前端跳转绑定流程。  
- `403_UPDATE_PWD`：Sys 账号密码超期未改，拦截除改密外所有接口。  
- `403_INFO_INCOMPLETE`：App 用户信息未补全，仅放行资料完善接口。

### 5.4 约束与约定
- 不混用 Sys 与 App 的用户体系与权限模型。  
- 微信授权优先使用 `unionId` 进行跨应用识别；若缺失则降级使用 `openId`。  
- 新增登录方式遵循 `{grantType}AppAuthStrategy` 命名与策略路由约定。

### 5.5 App 角色与关联关系
- 表结构与关系：
  - 用户表：`app_user`，参见 [ry_app.sql:app_user](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/script/sql/ry_app.sql#L6-L27)
  - 角色表：`app_role`（角色键如 `app_user`、`app_vip`），参见 [ry_app.sql:app_role](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/script/sql/ry_app.sql#L35-L53)
  - 关联表：`app_user_role`（多对多关联），参见 [ry_app.sql:app_user_role](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/script/sql/ry_app.sql#L56-L64)
- 规范说明：
  - App 端角色用于业务权益与标签管理（如普通用户、VIP），不等同于 Sys 端的 RBAC 功能权限。
  - 业务层根据 `role_key`（如 `app_vip`）判断权益与展示（价格、特权、活动资格等），避免与后台菜单/按钮权限混用。
  - 登录后构建的 `AppLoginUser` 可加载角色集合用于业务判定；权限校验仍以资源归属为主（基于 `userId`）。
- 第三方授权表：
  - `app_social_auth` 用于存储平台标识（`platform`/`platform_uid`）与微信 `open_id`/`union_id`，参见 [ry_app.sql:app_social_auth](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/script/sql/ry_app.sql#L67-L85)
  - App 微信登录优先使用 `union_id` 进行账号打通；若缺失则降级使用 `open_id`。

### 5.6 调用实例（curl）
- Sys 密码登录（grantType=password）：
```bash
curl -sS -X POST "http://localhost:8080/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "e5cd7e4891bf95d1d19206ce24a7b32e",
    "grantType": "password",
    "username": "admin",
    "password": "admin123",
    "code": "a1b2",
    "uuid": "captcha-uuid"
  }'
```
- Sys 短信登录（grantType=sms）：
```bash
curl -sS -X POST "http://localhost:8080/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "e5cd7e4891bf95d1d19206ce24a7b32e",
    "grantType": "sms",
    "phonenumber": "13800000000",
    "smsCode": "123456"
  }'
```
- Sys 邮箱登录（grantType=email）：
```bash
curl -sS -X POST "http://localhost:8080/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "e5cd7e4891bf95d1d19206ce24a7b32e",
    "grantType": "email",
    "email": "admin@example.com",
    "emailCode": "654321"
  }'
```
- Sys 第三方登录（grantType=social，source∈{github,gitee,wechat_open,wechat_mp…}）：
```bash
curl -sS -X POST "http://localhost:8080/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "e5cd7e4891bf95d1d19206ce24a7b32e",
    "grantType": "social",
    "source": "github",
    "socialCode": "oauth-code",
    "socialState": "state-123"
  }'
```
- App 密码登录（grantType=app_password）：
```bash
curl -sS -X POST "http://localhost:8080/app/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "428a8310cd442757ae699df5d894f051",
    "grantType": "app_password",
    "username": "appuser",
    "password": "admin123"
  }'
```
- App 短信登录（grantType=sms）：
```bash
curl -sS -X POST "http://localhost:8080/app/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "428a8310cd442757ae699df5d894f051",
    "grantType": "sms",
    "phonenumber": "13800000000",
    "smsCode": "123456"
  }'
```
- App 邮箱登录（grantType=email）：
```bash
curl -sS -X POST "http://localhost:8080/app/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "428a8310cd442757ae699df5d894f051",
    "grantType": "email",
    "email": "user@example.com",
    "emailCode": "654321"
  }'
```
- App 第三方登录（grantType=social，source∈{github,gitee,wechat_open…}）：
```bash
curl -sS -X POST "http://localhost:8080/app/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "428a8310cd442757ae699df5d894f051",
    "grantType": "social",
    "source": "gitee",
    "socialCode": "oauth-code",
    "socialState": "state-xyz"
  }'
```
- App 微信公众号登录（grantType=wechat_mp，前端已拿到 code 与 state）：
```bash
curl -sS -X POST "http://localhost:8080/app/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "428a8310cd442757ae699df5d894f051",
    "grantType": "wechat_mp",
    "socialCode": "wx-oauth-code",
    "socialState": "state-123"
  }'
```
- App 微信开放平台登录（grantType=wechat_open）：
```bash
curl -sS -X POST "http://localhost:8080/app/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "428a8310cd442757ae699df5d894f051",
    "grantType": "wechat_open",
    "socialCode": "wx-open-code",
    "socialState": "state-456"
  }'
```
- App 微信小程序登录（grantType=wechat_miniprogram）：
```bash
curl -sS -X POST "http://localhost:8080/app/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "428a8310cd442757ae699df5d894f051",
    "grantType": "wechat_miniprogram",
    "socialCode": "wx-mini-code",
    "socialState": "state-789"
  }'
```
- Sys 管理员绑定二维码（生成永久二维码 ticket 与 URL）：
```bash
# 生成永久二维码，scene_str = sys_user:{userId}
curl -sS -X POST "http://localhost:8080/wx/mp/qrcode/{appid}/forever" \
  -d "sceneStr=sys_user:1"

# 根据 ticket 获取二维码 URL
curl -sS -X GET "http://localhost:8080/wx/mp/qrcode/{appid}/url" \
  --data-urlencode "ticket=YOUR_TICKET"
```
- 获取公众号配置：
```bash
curl -sS "http://localhost:8080/wx/mp/portal/{appid}/config"
```
- App 用户信息补全白名单接口示例（占位）：
```bash
# 获取个人信息
curl -sS "http://localhost:8080/app/user/profile" -H "Authorization: Bearer YOUR_TOKEN"

# 绑定手机号
curl -sS -X POST "http://localhost:8080/app/user/bind" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{ "phone": "13800000000", "smsCode": "123456" }'
```
- Sys 退出登录：
```bash
curl -sS -X POST "http://localhost:8080/auth/logout" \
  -H "Authorization: Bearer YOUR_TOKEN"
```
- App 退出登录：
```bash
curl -sS -X POST "http://localhost:8080/app/auth/logout" \
  -H "Authorization: Bearer YOUR_TOKEN"
```
- Sys 用户注册：
```bash
curl -sS -X POST "http://localhost:8080/auth/register" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "newuser",
    "password": "password123",
    "userType": "sys_user",
    "code": "a1b2",
    "uuid": "captcha-uuid"
  }'
```
- App 用户注册：
```bash
curl -sS -X POST "http://localhost:8080/app/auth/register" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "appuser",
    "password": "password123"
  }'
```
- 获取图形验证码：
```bash
curl -sS "http://localhost:8080/auth/code"
# 返回: {"code":200,"data":{"uuid":"xxx","img":"data:image/png;base64,...","captchaEnabled":true}}
```
- 获取短信验证码：
```bash
curl -sS "http://localhost:8080/resource/sms/code?phonenumber=13800000000"
```
- 获取邮箱验证码：
```bash
curl -sS "http://localhost:8080/resource/email/code?email=user@example.com"
```
- 获取App配置：
```bash
curl -sS "http://localhost:8080/app/auth/config"
# 返回: {"code":200,"data":{"registerEnabled":true}}
```
- Sys 获取第三方绑定URL：
```bash
curl -sS "http://localhost:8080/auth/binding/github?domain=http://localhost:8080"
# 返回: {"code":200,"data":"https://github.com/login/oauth/authorize?..."}
```
- Sys 第三方绑定回调：
```bash
curl -sS -X POST "http://localhost:8080/auth/social/callback" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{
    "source": "github",
    "socialCode": "oauth-code",
    "socialState": "state-123"
  }'
```
- Sys 取消第三方绑定：
```bash
curl -sS -X DELETE "http://localhost:8080/auth/unlock/1" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

---

## 6. App 会话管理 API

- 基础路径：`/app/session`  
- 鉴权：登录态（Sa-Token）

### 6.1 接口列表
- `GET /app/session/active` 获取当前用户活跃会话列表
- `POST /app/session/terminate` 终止指定会话（参数：`sessionId`）
- `POST /app/session/heartbeat` 会话续期（参数：`sessionId`，默认延长至 30 天）
- `GET /app/session/sse` 订阅会话事件（SSE），事件名：`session`，数据格式：`<TYPE>:<SESSION_ID>`

### 6.2 会话数据结构（AppSession）
- `sessionId` 会话ID（token值）
- `userId` 用户ID
- `deviceType` 设备类型（Web/iOS/Android/Desktop）
- `deviceId` 设备标识（`X-Device-Id` 或生成）
- `userAgent` UA 字符串
- `ip` 登录IP
- `location` 地理位置（预留）
- `loginAt` 登录时间戳（毫秒）
- `expireAt` 过期时间戳（毫秒）
- `active` 活跃状态
- `token` 令牌原文

### 6.3 存储键规范
- 索引：`APP:SESS_INDEX:{userId}`
- 会话：`APP:SESS:{userId}:{sessionId}`（TTL 与 token 同步）
- 事件通道：`APP:SESS_EVT:{userId}`

### 6.4 调用示例（curl）
- 获取活跃会话：
```bash
curl -sS "http://localhost:8080/app/session/active" \
  -H "Authorization: Bearer YOUR_TOKEN"
```
- 终止指定会话：
```bash
curl -sS -X POST "http://localhost:8080/app/session/terminate" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{ "sessionId": "TOKEN_VALUE_TO_TERMINATE" }'
```
- 会话续期（心跳）：
```bash
curl -sS -X POST "http://localhost:8080/app/session/heartbeat" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{ "sessionId": "CURRENT_TOKEN_VALUE" }'
```
- 订阅会话事件（SSE）：
```bash
curl -sS "http://localhost:8080/app/session/sse" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### 6.5 优化建议
- 统一设备标识头 `X-Device-Id`，策略层在登录时读取并写入会话，便于同账号多设备管理。
- 事件命名与负载标准化：`<TYPE>:<SESSION_ID>`（TYPE ∈ {login, logout, heartbeat, terminate}）。
- TTL 与 Sa-Token 同步：确保 `APP:SESS:{userId}:{sessionId}` 的过期时间与 Token 过期保持一致，避免“僵尸会话”。

---

## 7. Sys 在线用户管理 API

- 基础路径：`/monitor/online`  
- 鉴权：登录态（Sa-Token），需要权限 `monitor:online:*`

### 7.1 接口列表
- `GET /monitor/online/list` 获取在线用户监控列表（支持按IP、用户名筛选）
- `GET /monitor/online` 获取当前用户登录的在线设备列表
- `DELETE /monitor/online/{tokenId}` 强退指定用户（需要权限 `monitor:online:forceLogout`）
- `DELETE /monitor/online/myself/{tokenId}` 强退当前用户的指定设备

### 7.2 在线用户数据结构（SysUserOnline）
- `tokenId` 会话编号（Token值）
- `userName` 用户名称
- `deptName` 部门名称
- `clientKey` 客户端标识
- `deviceType` 设备类型
- `ipaddr` 登录IP地址
- `loginLocation` 登录地点
- `browser` 浏览器类型
- `os` 操作系统
- `loginTime` 登录时间（时间戳，毫秒）

### 7.3 调用示例（curl）
- 获取在线用户列表：
```bash
curl -sS "http://localhost:8080/monitor/online/list?ipaddr=127.0.0.1&userName=admin" \
  -H "Authorization: Bearer YOUR_TOKEN"
```
- 获取当前用户在线设备：
```bash
curl -sS "http://localhost:8080/monitor/online" \
  -H "Authorization: Bearer YOUR_TOKEN"
```
- 强退指定用户：
```bash
curl -sS -X DELETE "http://localhost:8080/monitor/online/TOKEN_VALUE" \
  -H "Authorization: Bearer YOUR_TOKEN"
```
- 强退当前用户的指定设备：
```bash
curl -sS -X DELETE "http://localhost:8080/monitor/online/myself/TOKEN_VALUE" \
  -H "Authorization: Bearer YOUR_TOKEN"
```
- **代码路径**：[SysUserOnlineController](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java)

---

## 8. Sys 登录日志管理 API

- 基础路径：`/monitor/logininfor`  
- 鉴权：登录态（Sa-Token），需要权限 `monitor:logininfor:*`

### 8.1 接口列表
- `GET /monitor/logininfor/list` 获取系统访问记录列表（分页，支持按IP、状态、用户名、时间范围筛选）
- `POST /monitor/logininfor/export` 导出系统访问记录列表（需要权限 `monitor:logininfor:export`）
- `DELETE /monitor/logininfor/{infoIds}` 批量删除登录日志（需要权限 `monitor:logininfor:remove`）
- `DELETE /monitor/logininfor/clean` 清理系统访问记录（需要权限 `monitor:logininfor:remove`）
- `GET /monitor/logininfor/unlock/{userName}` 解锁指定用户的登录锁定（需要权限 `monitor:logininfor:unlock`）

### 8.2 登录日志数据结构（SysLogininfor）
- `infoId` 日志ID
- `userName` 用户账号
- `clientKey` 客户端标识
- `deviceType` 设备类型
- `status` 登录状态（0成功 1失败）
- `ipaddr` 登录IP地址
- `loginLocation` 登录地点
- `browser` 浏览器类型
- `os` 操作系统
- `msg` 提示消息
- `loginTime` 访问时间

### 8.3 调用示例（curl）
- 获取登录日志列表：
```bash
curl -sS "http://localhost:8080/monitor/logininfor/list?ipaddr=127.0.0.1&status=0&userName=admin&beginTime=2024-01-01&endTime=2024-12-31&pageNum=1&pageSize=10" \
  -H "Authorization: Bearer YOUR_TOKEN"
```
- 导出登录日志：
```bash
curl -sS -X POST "http://localhost:8080/monitor/logininfor/export" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -o logininfor.xlsx
```
- 批量删除登录日志：
```bash
curl -sS -X DELETE "http://localhost:8080/monitor/logininfor/1,2,3" \
  -H "Authorization: Bearer YOUR_TOKEN"
```
- 清理登录日志：
```bash
curl -sS -X DELETE "http://localhost:8080/monitor/logininfor/clean" \
  -H "Authorization: Bearer YOUR_TOKEN"
```
- 解锁用户登录：
```bash
curl -sS "http://localhost:8080/monitor/logininfor/unlock/admin" \
  -H "Authorization: Bearer YOUR_TOKEN"
```
- **代码路径**：[SysLogininforController](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java)

---

## 9. 相关代码路径参考

### 9.1 核心控制器
- **Sys登录控制器**：[AuthController](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/controller/AuthController.java)
- **App登录控制器**：[AppAuthController](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/controller/AppAuthController.java)
- **验证码控制器**：[CaptchaController](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/controller/CaptchaController.java)

### 9.2 核心服务
- **Sys登录服务**：[SysLoginService](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/service/SysLoginService.java)
- **App登录服务**：[AppLoginService](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/service/AppLoginService.java)
- **Sys注册服务**：[SysRegisterService](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/service/SysRegisterService.java)

### 9.3 登录策略
- **Sys策略接口**：[IAuthStrategy](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/service/IAuthStrategy.java)
- **App策略接口**：[IAppAuthStrategy](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/service/IAppAuthStrategy.java)
- **密码策略**：[PasswordAuthStrategy](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java), [AppPasswordAuthStrategy](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/service/impl/AppPasswordAuthStrategy.java)
- **短信策略**：[SmsAuthStrategy](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java), [AppSmsAuthStrategy](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/service/impl/AppSmsAuthStrategy.java)
- **邮箱策略**：[EmailAuthStrategy](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java), [AppEmailAuthStrategy](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/service/impl/AppEmailAuthStrategy.java)
- **第三方策略**：[SocialAuthStrategy](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java), [AppSocialAuthStrategy](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-server/src/main/java/org/dromara/app/service/impl/AppSocialAuthStrategy.java)

### 9.4 管理接口
- **在线用户管理**：[SysUserOnlineController](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java)
- **登录日志管理**：[SysLogininforController](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java)
- **登录日志服务**：[SysLogininforService](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/SysLogininforService.java), [SysLogininforServiceImpl](file:///Users/lihaha/Documents/Projecte/PoJie/PoJie/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java)

---

所有代码与配置参考项目既有实现与路径，确保可在 IDE 中点击跳转进行联查与验证。
