datai/docs/archive/decisions/adr/0007-login-history-query-and-auto-login.md

258 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: ADR-007
description: 查询不同类型ORG登录历史及自动登录功能
---
# 查询不同类型ORG登录历史及自动登录功能
## 元数据 (Metadata)
- **决策编号**: ADR-007
- **决策标题**: 查询不同类型ORG登录历史及自动登录功能
- **状态**: Accepted
- **日期**: 2026-01-16
- **最后更新**: 2026-01-18
- **决策者**: SSOT Architect
- **相关需求**: [REQ-007](../../requirements/REQ-007.md)
## 背景 (Context)
### 问题描述
当前系统支持通过 `DataISfLoginController` 进行 Salesforce 登录操作包括源ORG和目标ORG的登录。系统已经实现了基本的登录、登出、获取当前登录信息和自动登录功能。但是当前的 `getCurrentLoginInfo` 接口只能获取当前登录信息,无法查询历史登录记录。而 `autoLogin` 接口虽然支持自动登录,但只能使用最新的登录历史记录。
用户需要:
1. 查询不同类型ORG如Source、Target、Sandbox、Production等的成功登录历史记录
2. 基于指定的登录历史记录自动登录到对应的ORG环境
### 当前状态
- `DataISfLoginController` 已存在,包含以下接口:
- `POST /salesforce/login/doLogin` - 执行登录操作
- `POST /salesforce/login/logout` - 执行登出操作
- `GET /salesforce/login/current` - 获取当前登录信息
- `POST /salesforce/login/autoLogin` - 自动登录(使用最新历史)
- `IDataiSfLoginHistoryService` 已存在,包含查询登录历史的方法
- `DataiSfLoginHistory` 实体已存在,包含登录历史的所有字段
### 问题影响
1. 开发人员和测试人员无法快速查询特定类型的登录历史
2. 无法基于指定的历史记录自动登录到不同的ORG环境
3. 需要在多个环境间切换时,需要重复输入登录凭证,效率较低
### 约束条件
- 必须保持与现有代码风格的一致性
- 必须复用现有的 Service 层代码
- 必须确保接口的安全性和性能
- 必须支持多种ORG类型Source、Target、Sandbox、Production等
## 决策 (Decision)
### 决策内容
采用方案 A在现有的 `DataISfLoginController``DataiSfLoginHistoryController` 中新增三个接口:
1. `GET /salesforce/login/history/success/{orgType}` - 查询不同类型org成功登录历史
2. `POST /salesforce/login/autoLoginByHistory` - 根据对应登录成功历史登录不同的org
3. `GET /auth/history/latest-success-grouped` - 查询所有登录成功历史按username和instanceUrl分组每组返回最新一条数据
### 技术方案
#### 接口1: 查询不同类型org成功登录历史
**接口路径**: `GET /salesforce/login/history/success/{orgType}`
**功能描述**: 查询指定类型的成功登录历史记录
**实现方式**:
```java
@Operation(summary = "查询不同类型ORG成功登录历史")
@GetMapping("/history/success/{orgType}")
public AjaxResult getSuccessLoginHistoryByOrgType(@PathVariable String orgType) {
logger.info("接收到查询登录历史请求ORG类型: {}", orgType);
try {
List<DataiSfLoginHistory> historyList = loginHistoryService.selectSuccessLoginHistoryByOrgType(orgType);
return AjaxResult.success("查询成功", historyList);
} catch (Exception e) {
logger.error("查询登录历史请求处理失败: {}", e.getMessage(), e);
return AjaxResult.error("查询失败: " + e.getMessage());
}
}
```
**Service 层方法**:
```java
List<DataiSfLoginHistory> selectSuccessLoginHistoryByOrgType(String orgType);
```
#### 接口2: 根据对应登录成功历史登录不同的org
**接口路径**: `POST /salesforce/login/autoLoginByHistory`
**功能描述**: 根据指定的登录历史记录自动登录到对应ORG
**实现方式**:
```java
@Operation(summary = "根据登录历史自动登录")
@PostMapping("/autoLoginByHistory")
public AjaxResult autoLoginByHistory(@RequestBody Map<String, Long> request) {
Long historyId = request.get("historyId");
logger.info("接收到根据历史自动登录请求历史ID: {}", historyId);
try {
DataiSfLoginHistory loginHistory = loginHistoryService.selectDataiSfLoginHistoryById(historyId);
if (loginHistory == null) {
logger.warn("未找到ID为 {} 的登录历史记录", historyId);
return AjaxResult.error("未找到登录历史记录");
}
SalesforceLoginResult result = salesforceLoginService.autoLogin(historyHistory.getId());
if (result.isSuccess()) {
logger.info("自动登录成功用户ID: {}, 组织ID: {}, ORG类型: {}",
result.getUserId(), result.getOrganizationId(), result.getOrgType());
return AjaxResult.success("自动登录成功", result);
} else {
logger.warn("自动登录失败,错误码: {}, 错误信息: {}",
result.getErrorCode(), result.getErrorMessage());
return AjaxResult.error(result.getErrorCode(), result.getErrorMessage());
}
} catch (Exception e) {
logger.error("自动登录请求处理失败: {}", e.getMessage(), e);
return AjaxResult.error("自动登录失败: " + e.getMessage());
}
}
```
**Service 层方法**:
```java
DataiSfLoginHistory selectDataiSfLoginHistoryById(Long id);
```
#### 接口3: 查询所有登录成功历史分组数据
**接口路径**: `GET /auth/history/latest-success-grouped`
**功能描述**: 查询所有登录成功的历史记录按username和instanceUrl分组每组返回最新一条数据
**实现方式**:
```java
@Operation(summary = "查询所有登录成功的历史记录按username和instanceUrl分组每组返回最新一条")
@PreAuthorize("@ss.hasPermi('auth:history:list')")
@GetMapping("/latest-success-grouped")
public TableDataInfo listLatestSuccessGrouped()
{
List<DataiSfLoginHistory> list = dataiSfLoginHistoryService.selectLatestSuccessLoginHistoryGroupedByUserAndInstance();
List<DataiSfLoginHistoryVo> voList = list.stream().map(DataiSfLoginHistoryVo::objToVo).collect(Collectors.toList());
return getDataTableByPage(voList, voList.size());
}
```
**Service 层方法**:
```java
List<DataiSfLoginHistory> selectLatestSuccessLoginHistoryGroupedByUserAndInstance();
```
**SQL 实现**:
```sql
select * from (
select
<include refid="selectDataiSfLoginHistoryVo"/>,
ROW_NUMBER() OVER (PARTITION BY dslh.username, dslh.instance_url ORDER BY dslh.create_time DESC) as rn
from datai_sf_login_history dslh
where dslh.login_status = 'success'
) t where t.rn = 1
```
### 实施计划
1.`IDataiSfLoginHistoryService` 中添加新方法:
- `selectSuccessLoginHistoryByOrgType(String orgType)`
- `selectDataiSfLoginHistoryById(Long id)`
- `selectLatestSuccessLoginHistoryGroupedByUserAndInstance()`
2.`DataiSfLoginHistoryServiceImpl` 中实现新方法
3.`DataISfLoginController` 中添加两个新接口:
- `GET /salesforce/login/history/success/{orgType}`
- `POST /salesforce/login/autoLoginByHistory`
4.`DataiSfLoginHistoryController` 中添加新接口:
- `GET /auth/history/latest-success-grouped`
5.`DataiSfLoginHistoryMapper.xml` 中添加新的 SQL 查询语句
6. 编写单元测试和集成测试
7. 更新 API 文档
### 回滚策略
如果决策失败,可以:
1. 删除新增的两个接口
2. 删除 Service 层新增的方法
3. 回退到之前的代码版本
## 后果 (Consequences)
### 正面影响
1. **提高效率**: 用户可以快速查询登录历史,无需手动记录
2. **多环境支持**: 支持多种ORG类型的快速切换
3. **代码一致性**: 保持与现有代码风格的一致性
4. **开发成本低**: 复用现有代码,开发成本较低
### 负面影响
1. **Controller 膨胀**: Controller 可能会变得过于庞大
2. **维护复杂度**: 需要确保新增接口与现有接口的兼容性
### 风险评估
| 风险 | 概率 | 影响 | 缓解措施 |
|------|------|------|----------|
| 接口性能问题 | 低 | 中 | 添加索引,优化查询语句 |
| 安全性问题 | 低 | 高 | 确保登录历史中的敏感信息加密存储 |
| 兼容性问题 | 低 | 中 | 充分测试,确保与现有功能兼容 |
| 数据库查询性能 | 中 | 中 | 添加 orgType 字段索引 |
### 权衡分析
采用方案 A 的主要权衡是:
- **优点**: 开发成本低,代码一致性好,快速交付
- **缺点**: Controller 可能会变得过于庞大
- **结论**: 考虑到开发成本和代码一致性,以及现有架构的支持,选择方案 A 是合理的
## 合规性验证 (Compliance)
### 验证标准
1. 两个新接口已添加到 `DataISfLoginController`
2. Service 层新方法已实现
3. 接口功能符合需求文档中的验收标准
4. 接口性能满足非功能需求(响应时间 < 500ms
5. 接口安全性得到保证敏感信息加密
6. API 文档已更新
### 验证方法
1. 单元测试测试 Service 层新方法
2. 集成测试测试 Controller 层新接口
3. 性能测试测试接口响应时间
4. 安全测试测试敏感信息加密
5. 文档审查检查 API 文档是否完整
### 验证结果
待实施后填写
### 成功指标
| 指标 | 目标值 | 实际值 | 状态 |
|------|--------|--------|------|
| 接口数量 | 2 | 待验证 | 待验证 |
| 接口响应时间 | < 500ms | 待验证 | 待验证 |
| 接口可用性 | > 99.9% | 待验证 | 待验证 |
| 测试覆盖率 | > 80% | 待验证 | 待验证 |
## 相关文档 (Related Documents)
- [需求文档](../../requirements/REQ-007.md)
- [设计文档](../../design/0001-salesforce-cdc-realtime-sync.md)
- [其他 ADR](./0001-salesforce-cdc-sync.md)
- [DataISfLoginController](../../api-docs/auth/DataISfLoginController/) - Salesforce登录控制器接口文档
## 变更历史 (Change History)
| 日期 | 版本 | 变更内容 | 变更人 |
|------|------|----------|--------|
| 2026-01-16 | 1.0.0 | 初始版本 | SSOT Architect |