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

9.8 KiB
Raw Blame History

name description
ADR-007 查询不同类型ORG登录历史及自动登录功能

查询不同类型ORG登录历史及自动登录功能

元数据 (Metadata)

  • 决策编号: ADR-007
  • 决策标题: 查询不同类型ORG登录历史及自动登录功能
  • 状态: Accepted
  • 日期: 2026-01-16
  • 最后更新: 2026-01-18
  • 决策者: SSOT Architect
  • 相关需求: REQ-007

背景 (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在现有的 DataISfLoginControllerDataiSfLoginHistoryController 中新增三个接口:

  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}

功能描述: 查询指定类型的成功登录历史记录

实现方式:

@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 层方法:

List<DataiSfLoginHistory> selectSuccessLoginHistoryByOrgType(String orgType);

接口2: 根据对应登录成功历史登录不同的org

接口路径: POST /salesforce/login/autoLoginByHistory

功能描述: 根据指定的登录历史记录自动登录到对应ORG

实现方式:

@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 层方法:

DataiSfLoginHistory selectDataiSfLoginHistoryById(Long id);

接口3: 查询所有登录成功历史分组数据

接口路径: GET /auth/history/latest-success-grouped

功能描述: 查询所有登录成功的历史记录按username和instanceUrl分组每组返回最新一条数据

实现方式:

@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 层方法:

List<DataiSfLoginHistory> selectLatestSuccessLoginHistoryGroupedByUserAndInstance();

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% 待验证 待验证

变更历史 (Change History)

日期 版本 变更内容 变更人
2026-01-16 1.0.0 初始版本 SSOT Architect