datai/datai-scenes/datai-scene-salesforce/docs/decisions/adr/0007-login-history-query-and-auto-login.md

258 lines
9.8 KiB
Markdown
Raw Normal View History

---
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 |