diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/pom.xml b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/pom.xml
new file mode 100644
index 00000000..106c0c8b
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/pom.xml
@@ -0,0 +1,31 @@
+
+
+ 4.0.0
+
+ com.datai
+ datai-scene-salesforce
+ 1.0.0
+
+
+ datai-salesforce-auth
+
+
+ 22
+ 22
+ UTF-8
+
+
+
+
+ com.datai
+ datai-salesforce-common
+
+
+ com.datai
+ datai-cache-redis
+ ${datai.version}
+
+
+
\ No newline at end of file
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfFailedLoginController.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfFailedLoginController.java
new file mode 100644
index 00000000..e300f142
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfFailedLoginController.java
@@ -0,0 +1,113 @@
+package com.datai.auth.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.datai.common.annotation.Log;
+import com.datai.common.core.controller.BaseController;
+import com.datai.common.core.domain.AjaxResult;
+import com.datai.common.enums.BusinessType;
+import com.datai.auth.domain.DataiSfFailedLogin;
+import com.datai.auth.service.IDataiSfFailedLoginService;
+import com.datai.common.utils.poi.ExcelUtil;
+import com.datai.common.core.page.TableDataInfo;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+
+/**
+ * 失败登录Controller
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@RestController
+@RequestMapping("/auth/login")
+@Tag(name = "【失败登录】管理")
+public class DataiSfFailedLoginController extends BaseController
+{
+ @Autowired
+ private IDataiSfFailedLoginService dataiSfFailedLoginService;
+
+ /**
+ * 查询失败登录列表
+ */
+ @Operation(summary = "查询失败登录列表")
+ @PreAuthorize("@ss.hasPermi('auth:login:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(DataiSfFailedLogin dataiSfFailedLogin)
+ {
+ startPage();
+ List list = dataiSfFailedLoginService.selectDataiSfFailedLoginList(dataiSfFailedLogin);
+ return getDataTable(list);
+ }
+
+ /**
+ * 导出失败登录列表
+ */
+ @Operation(summary = "导出失败登录列表")
+ @PreAuthorize("@ss.hasPermi('auth:login:export')")
+ @Log(title = "失败登录", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, DataiSfFailedLogin dataiSfFailedLogin)
+ {
+ List list = dataiSfFailedLoginService.selectDataiSfFailedLoginList(dataiSfFailedLogin);
+ ExcelUtil util = new ExcelUtil(DataiSfFailedLogin.class);
+ util.exportExcel(response, list, "失败登录数据");
+ }
+
+ /**
+ * 获取失败登录详细信息
+ */
+ @Operation(summary = "获取失败登录详细信息")
+ @PreAuthorize("@ss.hasPermi('auth:login:query')")
+ @GetMapping(value = "/{failedId}")
+ public AjaxResult getInfo(@PathVariable("failedId") Long failedId)
+ {
+ return success(dataiSfFailedLoginService.selectDataiSfFailedLoginByFailedId(failedId));
+ }
+
+ /**
+ * 新增失败登录
+ */
+ @Operation(summary = "新增失败登录")
+ @PreAuthorize("@ss.hasPermi('auth:login:add')")
+ @Log(title = "失败登录", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody DataiSfFailedLogin dataiSfFailedLogin)
+ {
+ return toAjax(dataiSfFailedLoginService.insertDataiSfFailedLogin(dataiSfFailedLogin));
+ }
+
+ /**
+ * 修改失败登录
+ */
+ @Operation(summary = "修改失败登录")
+ @PreAuthorize("@ss.hasPermi('auth:login:edit')")
+ @Log(title = "失败登录", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody DataiSfFailedLogin dataiSfFailedLogin)
+ {
+ return toAjax(dataiSfFailedLoginService.updateDataiSfFailedLogin(dataiSfFailedLogin));
+ }
+
+ /**
+ * 删除失败登录
+ */
+ @Operation(summary = "删除失败登录")
+ @PreAuthorize("@ss.hasPermi('auth:login:remove')")
+ @Log(title = "失败登录", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{failedIds}")
+ public AjaxResult remove(@PathVariable( name = "failedIds" ) Long[] failedIds)
+ {
+ return toAjax(dataiSfFailedLoginService.deleteDataiSfFailedLoginByFailedIds(failedIds));
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfLoginAuditController.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfLoginAuditController.java
new file mode 100644
index 00000000..b89c0951
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfLoginAuditController.java
@@ -0,0 +1,113 @@
+package com.datai.auth.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.datai.common.annotation.Log;
+import com.datai.common.core.controller.BaseController;
+import com.datai.common.core.domain.AjaxResult;
+import com.datai.common.enums.BusinessType;
+import com.datai.auth.domain.DataiSfLoginAudit;
+import com.datai.auth.service.IDataiSfLoginAuditService;
+import com.datai.common.utils.poi.ExcelUtil;
+import com.datai.common.core.page.TableDataInfo;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+
+/**
+ * 登录审计日志Controller
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@RestController
+@RequestMapping("/auth/audit")
+@Tag(name = "【登录审计日志】管理")
+public class DataiSfLoginAuditController extends BaseController
+{
+ @Autowired
+ private IDataiSfLoginAuditService dataiSfLoginAuditService;
+
+ /**
+ * 查询登录审计日志列表
+ */
+ @Operation(summary = "查询登录审计日志列表")
+ @PreAuthorize("@ss.hasPermi('auth:audit:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(DataiSfLoginAudit dataiSfLoginAudit)
+ {
+ startPage();
+ List list = dataiSfLoginAuditService.selectDataiSfLoginAuditList(dataiSfLoginAudit);
+ return getDataTable(list);
+ }
+
+ /**
+ * 导出登录审计日志列表
+ */
+ @Operation(summary = "导出登录审计日志列表")
+ @PreAuthorize("@ss.hasPermi('auth:audit:export')")
+ @Log(title = "登录审计日志", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, DataiSfLoginAudit dataiSfLoginAudit)
+ {
+ List list = dataiSfLoginAuditService.selectDataiSfLoginAuditList(dataiSfLoginAudit);
+ ExcelUtil util = new ExcelUtil(DataiSfLoginAudit.class);
+ util.exportExcel(response, list, "登录审计日志数据");
+ }
+
+ /**
+ * 获取登录审计日志详细信息
+ */
+ @Operation(summary = "获取登录审计日志详细信息")
+ @PreAuthorize("@ss.hasPermi('auth:audit:query')")
+ @GetMapping(value = "/{auditId}")
+ public AjaxResult getInfo(@PathVariable("auditId") Long auditId)
+ {
+ return success(dataiSfLoginAuditService.selectDataiSfLoginAuditByAuditId(auditId));
+ }
+
+ /**
+ * 新增登录审计日志
+ */
+ @Operation(summary = "新增登录审计日志")
+ @PreAuthorize("@ss.hasPermi('auth:audit:add')")
+ @Log(title = "登录审计日志", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody DataiSfLoginAudit dataiSfLoginAudit)
+ {
+ return toAjax(dataiSfLoginAuditService.insertDataiSfLoginAudit(dataiSfLoginAudit));
+ }
+
+ /**
+ * 修改登录审计日志
+ */
+ @Operation(summary = "修改登录审计日志")
+ @PreAuthorize("@ss.hasPermi('auth:audit:edit')")
+ @Log(title = "登录审计日志", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody DataiSfLoginAudit dataiSfLoginAudit)
+ {
+ return toAjax(dataiSfLoginAuditService.updateDataiSfLoginAudit(dataiSfLoginAudit));
+ }
+
+ /**
+ * 删除登录审计日志
+ */
+ @Operation(summary = "删除登录审计日志")
+ @PreAuthorize("@ss.hasPermi('auth:audit:remove')")
+ @Log(title = "登录审计日志", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{auditIds}")
+ public AjaxResult remove(@PathVariable( name = "auditIds" ) Long[] auditIds)
+ {
+ return toAjax(dataiSfLoginAuditService.deleteDataiSfLoginAuditByAuditIds(auditIds));
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfLoginSessionController.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfLoginSessionController.java
new file mode 100644
index 00000000..149416fc
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfLoginSessionController.java
@@ -0,0 +1,113 @@
+package com.datai.auth.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.datai.common.annotation.Log;
+import com.datai.common.core.controller.BaseController;
+import com.datai.common.core.domain.AjaxResult;
+import com.datai.common.enums.BusinessType;
+import com.datai.auth.domain.DataiSfLoginSession;
+import com.datai.auth.service.IDataiSfLoginSessionService;
+import com.datai.common.utils.poi.ExcelUtil;
+import com.datai.common.core.page.TableDataInfo;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+
+/**
+ * 登录会话Controller
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@RestController
+@RequestMapping("/auth/session")
+@Tag(name = "【登录会话】管理")
+public class DataiSfLoginSessionController extends BaseController
+{
+ @Autowired
+ private IDataiSfLoginSessionService dataiSfLoginSessionService;
+
+ /**
+ * 查询登录会话列表
+ */
+ @Operation(summary = "查询登录会话列表")
+ @PreAuthorize("@ss.hasPermi('auth:session:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(DataiSfLoginSession dataiSfLoginSession)
+ {
+ startPage();
+ List list = dataiSfLoginSessionService.selectDataiSfLoginSessionList(dataiSfLoginSession);
+ return getDataTable(list);
+ }
+
+ /**
+ * 导出登录会话列表
+ */
+ @Operation(summary = "导出登录会话列表")
+ @PreAuthorize("@ss.hasPermi('auth:session:export')")
+ @Log(title = "登录会话", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, DataiSfLoginSession dataiSfLoginSession)
+ {
+ List list = dataiSfLoginSessionService.selectDataiSfLoginSessionList(dataiSfLoginSession);
+ ExcelUtil util = new ExcelUtil(DataiSfLoginSession.class);
+ util.exportExcel(response, list, "登录会话数据");
+ }
+
+ /**
+ * 获取登录会话详细信息
+ */
+ @Operation(summary = "获取登录会话详细信息")
+ @PreAuthorize("@ss.hasPermi('auth:session:query')")
+ @GetMapping(value = "/{sessionId}")
+ public AjaxResult getInfo(@PathVariable("sessionId") Long sessionId)
+ {
+ return success(dataiSfLoginSessionService.selectDataiSfLoginSessionBySessionId(sessionId));
+ }
+
+ /**
+ * 新增登录会话
+ */
+ @Operation(summary = "新增登录会话")
+ @PreAuthorize("@ss.hasPermi('auth:session:add')")
+ @Log(title = "登录会话", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody DataiSfLoginSession dataiSfLoginSession)
+ {
+ return toAjax(dataiSfLoginSessionService.insertDataiSfLoginSession(dataiSfLoginSession));
+ }
+
+ /**
+ * 修改登录会话
+ */
+ @Operation(summary = "修改登录会话")
+ @PreAuthorize("@ss.hasPermi('auth:session:edit')")
+ @Log(title = "登录会话", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody DataiSfLoginSession dataiSfLoginSession)
+ {
+ return toAjax(dataiSfLoginSessionService.updateDataiSfLoginSession(dataiSfLoginSession));
+ }
+
+ /**
+ * 删除登录会话
+ */
+ @Operation(summary = "删除登录会话")
+ @PreAuthorize("@ss.hasPermi('auth:session:remove')")
+ @Log(title = "登录会话", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{sessionIds}")
+ public AjaxResult remove(@PathVariable( name = "sessionIds" ) Long[] sessionIds)
+ {
+ return toAjax(dataiSfLoginSessionService.deleteDataiSfLoginSessionBySessionIds(sessionIds));
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfLoginStatisticsController.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfLoginStatisticsController.java
new file mode 100644
index 00000000..f64de9ac
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfLoginStatisticsController.java
@@ -0,0 +1,113 @@
+package com.datai.auth.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.datai.common.annotation.Log;
+import com.datai.common.core.controller.BaseController;
+import com.datai.common.core.domain.AjaxResult;
+import com.datai.common.enums.BusinessType;
+import com.datai.auth.domain.DataiSfLoginStatistics;
+import com.datai.auth.service.IDataiSfLoginStatisticsService;
+import com.datai.common.utils.poi.ExcelUtil;
+import com.datai.common.core.page.TableDataInfo;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+
+/**
+ * 登录统计Controller
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@RestController
+@RequestMapping("/auth/statistics")
+@Tag(name = "【登录统计】管理")
+public class DataiSfLoginStatisticsController extends BaseController
+{
+ @Autowired
+ private IDataiSfLoginStatisticsService dataiSfLoginStatisticsService;
+
+ /**
+ * 查询登录统计列表
+ */
+ @Operation(summary = "查询登录统计列表")
+ @PreAuthorize("@ss.hasPermi('auth:statistics:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(DataiSfLoginStatistics dataiSfLoginStatistics)
+ {
+ startPage();
+ List list = dataiSfLoginStatisticsService.selectDataiSfLoginStatisticsList(dataiSfLoginStatistics);
+ return getDataTable(list);
+ }
+
+ /**
+ * 导出登录统计列表
+ */
+ @Operation(summary = "导出登录统计列表")
+ @PreAuthorize("@ss.hasPermi('auth:statistics:export')")
+ @Log(title = "登录统计", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, DataiSfLoginStatistics dataiSfLoginStatistics)
+ {
+ List list = dataiSfLoginStatisticsService.selectDataiSfLoginStatisticsList(dataiSfLoginStatistics);
+ ExcelUtil util = new ExcelUtil(DataiSfLoginStatistics.class);
+ util.exportExcel(response, list, "登录统计数据");
+ }
+
+ /**
+ * 获取登录统计详细信息
+ */
+ @Operation(summary = "获取登录统计详细信息")
+ @PreAuthorize("@ss.hasPermi('auth:statistics:query')")
+ @GetMapping(value = "/{statId}")
+ public AjaxResult getInfo(@PathVariable("statId") Long statId)
+ {
+ return success(dataiSfLoginStatisticsService.selectDataiSfLoginStatisticsByStatId(statId));
+ }
+
+ /**
+ * 新增登录统计
+ */
+ @Operation(summary = "新增登录统计")
+ @PreAuthorize("@ss.hasPermi('auth:statistics:add')")
+ @Log(title = "登录统计", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody DataiSfLoginStatistics dataiSfLoginStatistics)
+ {
+ return toAjax(dataiSfLoginStatisticsService.insertDataiSfLoginStatistics(dataiSfLoginStatistics));
+ }
+
+ /**
+ * 修改登录统计
+ */
+ @Operation(summary = "修改登录统计")
+ @PreAuthorize("@ss.hasPermi('auth:statistics:edit')")
+ @Log(title = "登录统计", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody DataiSfLoginStatistics dataiSfLoginStatistics)
+ {
+ return toAjax(dataiSfLoginStatisticsService.updateDataiSfLoginStatistics(dataiSfLoginStatistics));
+ }
+
+ /**
+ * 删除登录统计
+ */
+ @Operation(summary = "删除登录统计")
+ @PreAuthorize("@ss.hasPermi('auth:statistics:remove')")
+ @Log(title = "登录统计", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{statIds}")
+ public AjaxResult remove(@PathVariable( name = "statIds" ) Long[] statIds)
+ {
+ return toAjax(dataiSfLoginStatisticsService.deleteDataiSfLoginStatisticsByStatIds(statIds));
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfTokenBindingController.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfTokenBindingController.java
new file mode 100644
index 00000000..93c2c59a
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfTokenBindingController.java
@@ -0,0 +1,113 @@
+package com.datai.auth.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.datai.common.annotation.Log;
+import com.datai.common.core.controller.BaseController;
+import com.datai.common.core.domain.AjaxResult;
+import com.datai.common.enums.BusinessType;
+import com.datai.auth.domain.DataiSfTokenBinding;
+import com.datai.auth.service.IDataiSfTokenBindingService;
+import com.datai.common.utils.poi.ExcelUtil;
+import com.datai.common.core.page.TableDataInfo;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+
+/**
+ * 令牌绑定Controller
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@RestController
+@RequestMapping("/auth/binding")
+@Tag(name = "【令牌绑定】管理")
+public class DataiSfTokenBindingController extends BaseController
+{
+ @Autowired
+ private IDataiSfTokenBindingService dataiSfTokenBindingService;
+
+ /**
+ * 查询令牌绑定列表
+ */
+ @Operation(summary = "查询令牌绑定列表")
+ @PreAuthorize("@ss.hasPermi('auth:binding:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(DataiSfTokenBinding dataiSfTokenBinding)
+ {
+ startPage();
+ List list = dataiSfTokenBindingService.selectDataiSfTokenBindingList(dataiSfTokenBinding);
+ return getDataTable(list);
+ }
+
+ /**
+ * 导出令牌绑定列表
+ */
+ @Operation(summary = "导出令牌绑定列表")
+ @PreAuthorize("@ss.hasPermi('auth:binding:export')")
+ @Log(title = "令牌绑定", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, DataiSfTokenBinding dataiSfTokenBinding)
+ {
+ List list = dataiSfTokenBindingService.selectDataiSfTokenBindingList(dataiSfTokenBinding);
+ ExcelUtil util = new ExcelUtil(DataiSfTokenBinding.class);
+ util.exportExcel(response, list, "令牌绑定数据");
+ }
+
+ /**
+ * 获取令牌绑定详细信息
+ */
+ @Operation(summary = "获取令牌绑定详细信息")
+ @PreAuthorize("@ss.hasPermi('auth:binding:query')")
+ @GetMapping(value = "/{bindingId}")
+ public AjaxResult getInfo(@PathVariable("bindingId") Long bindingId)
+ {
+ return success(dataiSfTokenBindingService.selectDataiSfTokenBindingByBindingId(bindingId));
+ }
+
+ /**
+ * 新增令牌绑定
+ */
+ @Operation(summary = "新增令牌绑定")
+ @PreAuthorize("@ss.hasPermi('auth:binding:add')")
+ @Log(title = "令牌绑定", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody DataiSfTokenBinding dataiSfTokenBinding)
+ {
+ return toAjax(dataiSfTokenBindingService.insertDataiSfTokenBinding(dataiSfTokenBinding));
+ }
+
+ /**
+ * 修改令牌绑定
+ */
+ @Operation(summary = "修改令牌绑定")
+ @PreAuthorize("@ss.hasPermi('auth:binding:edit')")
+ @Log(title = "令牌绑定", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody DataiSfTokenBinding dataiSfTokenBinding)
+ {
+ return toAjax(dataiSfTokenBindingService.updateDataiSfTokenBinding(dataiSfTokenBinding));
+ }
+
+ /**
+ * 删除令牌绑定
+ */
+ @Operation(summary = "删除令牌绑定")
+ @PreAuthorize("@ss.hasPermi('auth:binding:remove')")
+ @Log(title = "令牌绑定", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{bindingIds}")
+ public AjaxResult remove(@PathVariable( name = "bindingIds" ) Long[] bindingIds)
+ {
+ return toAjax(dataiSfTokenBindingService.deleteDataiSfTokenBindingByBindingIds(bindingIds));
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfTokenController.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfTokenController.java
new file mode 100644
index 00000000..51c55a38
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/controller/DataiSfTokenController.java
@@ -0,0 +1,113 @@
+package com.datai.auth.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.datai.common.annotation.Log;
+import com.datai.common.core.controller.BaseController;
+import com.datai.common.core.domain.AjaxResult;
+import com.datai.common.enums.BusinessType;
+import com.datai.auth.domain.DataiSfToken;
+import com.datai.auth.service.IDataiSfTokenService;
+import com.datai.common.utils.poi.ExcelUtil;
+import com.datai.common.core.page.TableDataInfo;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+
+/**
+ * 令牌Controller
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@RestController
+@RequestMapping("/auth/token")
+@Tag(name = "【令牌】管理")
+public class DataiSfTokenController extends BaseController
+{
+ @Autowired
+ private IDataiSfTokenService dataiSfTokenService;
+
+ /**
+ * 查询令牌列表
+ */
+ @Operation(summary = "查询令牌列表")
+ @PreAuthorize("@ss.hasPermi('auth:token:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(DataiSfToken dataiSfToken)
+ {
+ startPage();
+ List list = dataiSfTokenService.selectDataiSfTokenList(dataiSfToken);
+ return getDataTable(list);
+ }
+
+ /**
+ * 导出令牌列表
+ */
+ @Operation(summary = "导出令牌列表")
+ @PreAuthorize("@ss.hasPermi('auth:token:export')")
+ @Log(title = "令牌", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, DataiSfToken dataiSfToken)
+ {
+ List list = dataiSfTokenService.selectDataiSfTokenList(dataiSfToken);
+ ExcelUtil util = new ExcelUtil(DataiSfToken.class);
+ util.exportExcel(response, list, "令牌数据");
+ }
+
+ /**
+ * 获取令牌详细信息
+ */
+ @Operation(summary = "获取令牌详细信息")
+ @PreAuthorize("@ss.hasPermi('auth:token:query')")
+ @GetMapping(value = "/{tokenId}")
+ public AjaxResult getInfo(@PathVariable("tokenId") Long tokenId)
+ {
+ return success(dataiSfTokenService.selectDataiSfTokenByTokenId(tokenId));
+ }
+
+ /**
+ * 新增令牌
+ */
+ @Operation(summary = "新增令牌")
+ @PreAuthorize("@ss.hasPermi('auth:token:add')")
+ @Log(title = "令牌", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody DataiSfToken dataiSfToken)
+ {
+ return toAjax(dataiSfTokenService.insertDataiSfToken(dataiSfToken));
+ }
+
+ /**
+ * 修改令牌
+ */
+ @Operation(summary = "修改令牌")
+ @PreAuthorize("@ss.hasPermi('auth:token:edit')")
+ @Log(title = "令牌", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody DataiSfToken dataiSfToken)
+ {
+ return toAjax(dataiSfTokenService.updateDataiSfToken(dataiSfToken));
+ }
+
+ /**
+ * 删除令牌
+ */
+ @Operation(summary = "删除令牌")
+ @PreAuthorize("@ss.hasPermi('auth:token:remove')")
+ @Log(title = "令牌", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{tokenIds}")
+ public AjaxResult remove(@PathVariable( name = "tokenIds" ) Long[] tokenIds)
+ {
+ return toAjax(dataiSfTokenService.deleteDataiSfTokenByTokenIds(tokenIds));
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfFailedLogin.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfFailedLogin.java
new file mode 100644
index 00000000..fdf079c8
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfFailedLogin.java
@@ -0,0 +1,233 @@
+package com.datai.auth.domain;
+
+import java.time.LocalDate;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.datai.common.annotation.Excel;
+import com.datai.common.core.domain.BaseEntity;
+
+/**
+ * 失败登录对象 datai_sf_failed_login
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@Schema(description = "失败登录对象")
+public class DataiSfFailedLogin extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+
+ /** 记录ID */
+ @Schema(title = "记录ID")
+ private Long failedId;
+
+ /** 租户编号 */
+ @Schema(title = "租户编号")
+ @Excel(name = "租户编号")
+ private String tenantId;
+
+ /** 用户名 */
+ @Schema(title = "用户名")
+ @Excel(name = "用户名")
+ private String username;
+
+ /** 登录类型 */
+ @Schema(title = "登录类型")
+ @Excel(name = "登录类型")
+ private String loginType;
+
+ /** 失败时间 */
+ @Schema(title = "失败时间")
+ @Excel(name = "失败时间")
+ private LocalDate failedTime;
+
+ /** 失败原因 */
+ @Schema(title = "失败原因")
+ @Excel(name = "失败原因")
+ private String failedReason;
+
+ /** IP地址 */
+ @Schema(title = "IP地址")
+ @Excel(name = "IP地址")
+ private String ipAddress;
+
+ /** 设备信息 */
+ @Schema(title = "设备信息")
+ @Excel(name = "设备信息")
+ private String deviceInfo;
+
+ /** 锁定状态 */
+ @Schema(title = "锁定状态")
+ @Excel(name = "锁定状态")
+ private String lockStatus;
+
+ /** 锁定时间 */
+ @Schema(title = "锁定时间")
+ @Excel(name = "锁定时间")
+ private LocalDate lockTime;
+
+ /** 解锁时间 */
+ @Schema(title = "解锁时间")
+ @Excel(name = "解锁时间")
+ private LocalDate unlockTime;
+
+ /** 锁定原因 */
+ @Schema(title = "锁定原因")
+ @Excel(name = "锁定原因")
+ private String lockReason;
+ public void setFailedId(Long failedId)
+ {
+ this.failedId = failedId;
+ }
+
+ public Long getFailedId()
+ {
+ return failedId;
+ }
+
+
+ public void setTenantId(String tenantId)
+ {
+ this.tenantId = tenantId;
+ }
+
+ public String getTenantId()
+ {
+ return tenantId;
+ }
+
+
+ public void setUsername(String username)
+ {
+ this.username = username;
+ }
+
+ public String getUsername()
+ {
+ return username;
+ }
+
+
+ public void setLoginType(String loginType)
+ {
+ this.loginType = loginType;
+ }
+
+ public String getLoginType()
+ {
+ return loginType;
+ }
+
+
+ public void setFailedTime(LocalDate failedTime)
+ {
+ this.failedTime = failedTime;
+ }
+
+ public LocalDate getFailedTime()
+ {
+ return failedTime;
+ }
+
+
+ public void setFailedReason(String failedReason)
+ {
+ this.failedReason = failedReason;
+ }
+
+ public String getFailedReason()
+ {
+ return failedReason;
+ }
+
+
+ public void setIpAddress(String ipAddress)
+ {
+ this.ipAddress = ipAddress;
+ }
+
+ public String getIpAddress()
+ {
+ return ipAddress;
+ }
+
+
+ public void setDeviceInfo(String deviceInfo)
+ {
+ this.deviceInfo = deviceInfo;
+ }
+
+ public String getDeviceInfo()
+ {
+ return deviceInfo;
+ }
+
+
+ public void setLockStatus(String lockStatus)
+ {
+ this.lockStatus = lockStatus;
+ }
+
+ public String getLockStatus()
+ {
+ return lockStatus;
+ }
+
+
+ public void setLockTime(LocalDate lockTime)
+ {
+ this.lockTime = lockTime;
+ }
+
+ public LocalDate getLockTime()
+ {
+ return lockTime;
+ }
+
+
+ public void setUnlockTime(LocalDate unlockTime)
+ {
+ this.unlockTime = unlockTime;
+ }
+
+ public LocalDate getUnlockTime()
+ {
+ return unlockTime;
+ }
+
+
+ public void setLockReason(String lockReason)
+ {
+ this.lockReason = lockReason;
+ }
+
+ public String getLockReason()
+ {
+ return lockReason;
+ }
+
+
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("failedId", getFailedId())
+ .append("tenantId", getTenantId())
+ .append("username", getUsername())
+ .append("loginType", getLoginType())
+ .append("failedTime", getFailedTime())
+ .append("failedReason", getFailedReason())
+ .append("ipAddress", getIpAddress())
+ .append("deviceInfo", getDeviceInfo())
+ .append("lockStatus", getLockStatus())
+ .append("lockTime", getLockTime())
+ .append("unlockTime", getUnlockTime())
+ .append("lockReason", getLockReason())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .toString();
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfLoginAudit.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfLoginAudit.java
new file mode 100644
index 00000000..bdfde249
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfLoginAudit.java
@@ -0,0 +1,267 @@
+package com.datai.auth.domain;
+
+import java.time.LocalDate;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.datai.common.annotation.Excel;
+import com.datai.common.core.domain.BaseEntity;
+
+/**
+ * 登录审计日志对象 datai_sf_login_audit
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@Schema(description = "登录审计日志对象")
+public class DataiSfLoginAudit extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+
+ /** 日志ID */
+ @Schema(title = "日志ID")
+ private Long auditId;
+
+ /** 租户编号 */
+ @Schema(title = "租户编号")
+ @Excel(name = "租户编号")
+ private String tenantId;
+
+ /** 用户名 */
+ @Schema(title = "用户名")
+ @Excel(name = "用户名")
+ private String username;
+
+ /** 操作类型 */
+ @Schema(title = "操作类型")
+ @Excel(name = "操作类型")
+ private String operationType;
+
+ /** 操作结果 */
+ @Schema(title = "操作结果")
+ @Excel(name = "操作结果")
+ private String result;
+
+ /** 操作时间 */
+ @Schema(title = "操作时间")
+ @Excel(name = "操作时间")
+ private LocalDate operationTime;
+
+ /** IP地址 */
+ @Schema(title = "IP地址")
+ @Excel(name = "IP地址")
+ private String ipAddress;
+
+ /** 设备信息 */
+ @Schema(title = "设备信息")
+ @Excel(name = "设备信息")
+ private String deviceInfo;
+
+ /** 浏览器信息 */
+ @Schema(title = "浏览器信息")
+ @Excel(name = "浏览器信息")
+ private String browserInfo;
+
+ /** 登录类型 */
+ @Schema(title = "登录类型")
+ @Excel(name = "登录类型")
+ private String loginType;
+
+ /** 错误信息 */
+ @Schema(title = "错误信息")
+ @Excel(name = "错误信息")
+ private String errorMessage;
+
+ /** 会话ID */
+ @Schema(title = "会话ID")
+ @Excel(name = "会话ID")
+ private Long sessionId;
+
+ /** 令牌ID */
+ @Schema(title = "令牌ID")
+ @Excel(name = "令牌ID")
+ private Long tokenId;
+
+ /** 请求ID */
+ @Schema(title = "请求ID")
+ @Excel(name = "请求ID")
+ private String requestId;
+ public void setAuditId(Long auditId)
+ {
+ this.auditId = auditId;
+ }
+
+ public Long getAuditId()
+ {
+ return auditId;
+ }
+
+
+ public void setTenantId(String tenantId)
+ {
+ this.tenantId = tenantId;
+ }
+
+ public String getTenantId()
+ {
+ return tenantId;
+ }
+
+
+ public void setUsername(String username)
+ {
+ this.username = username;
+ }
+
+ public String getUsername()
+ {
+ return username;
+ }
+
+
+ public void setOperationType(String operationType)
+ {
+ this.operationType = operationType;
+ }
+
+ public String getOperationType()
+ {
+ return operationType;
+ }
+
+
+ public void setResult(String result)
+ {
+ this.result = result;
+ }
+
+ public String getResult()
+ {
+ return result;
+ }
+
+
+ public void setOperationTime(LocalDate operationTime)
+ {
+ this.operationTime = operationTime;
+ }
+
+ public LocalDate getOperationTime()
+ {
+ return operationTime;
+ }
+
+
+ public void setIpAddress(String ipAddress)
+ {
+ this.ipAddress = ipAddress;
+ }
+
+ public String getIpAddress()
+ {
+ return ipAddress;
+ }
+
+
+ public void setDeviceInfo(String deviceInfo)
+ {
+ this.deviceInfo = deviceInfo;
+ }
+
+ public String getDeviceInfo()
+ {
+ return deviceInfo;
+ }
+
+
+ public void setBrowserInfo(String browserInfo)
+ {
+ this.browserInfo = browserInfo;
+ }
+
+ public String getBrowserInfo()
+ {
+ return browserInfo;
+ }
+
+
+ public void setLoginType(String loginType)
+ {
+ this.loginType = loginType;
+ }
+
+ public String getLoginType()
+ {
+ return loginType;
+ }
+
+
+ public void setErrorMessage(String errorMessage)
+ {
+ this.errorMessage = errorMessage;
+ }
+
+ public String getErrorMessage()
+ {
+ return errorMessage;
+ }
+
+
+ public void setSessionId(Long sessionId)
+ {
+ this.sessionId = sessionId;
+ }
+
+ public Long getSessionId()
+ {
+ return sessionId;
+ }
+
+
+ public void setTokenId(Long tokenId)
+ {
+ this.tokenId = tokenId;
+ }
+
+ public Long getTokenId()
+ {
+ return tokenId;
+ }
+
+
+ public void setRequestId(String requestId)
+ {
+ this.requestId = requestId;
+ }
+
+ public String getRequestId()
+ {
+ return requestId;
+ }
+
+
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("auditId", getAuditId())
+ .append("tenantId", getTenantId())
+ .append("username", getUsername())
+ .append("operationType", getOperationType())
+ .append("result", getResult())
+ .append("operationTime", getOperationTime())
+ .append("ipAddress", getIpAddress())
+ .append("deviceInfo", getDeviceInfo())
+ .append("browserInfo", getBrowserInfo())
+ .append("loginType", getLoginType())
+ .append("errorMessage", getErrorMessage())
+ .append("sessionId", getSessionId())
+ .append("tokenId", getTokenId())
+ .append("requestId", getRequestId())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .toString();
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfLoginSession.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfLoginSession.java
new file mode 100644
index 00000000..3ac90bee
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfLoginSession.java
@@ -0,0 +1,252 @@
+package com.datai.auth.domain;
+
+import java.time.LocalDate;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.datai.common.annotation.Excel;
+import com.datai.common.core.domain.BaseEntity;
+
+/**
+ * 登录会话对象 datai_sf_login_session
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@Schema(description = "登录会话对象")
+public class DataiSfLoginSession extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+
+ /** 会话ID */
+ @Schema(title = "会话ID")
+ private Long sessionId;
+
+ /** 租户编号 */
+ @Schema(title = "租户编号")
+ @Excel(name = "租户编号")
+ private String tenantId;
+
+ /** 用户名 */
+ @Schema(title = "用户名")
+ @Excel(name = "用户名")
+ private String username;
+
+ /** 登录类型 */
+ @Schema(title = "登录类型")
+ @Excel(name = "登录类型")
+ private String loginType;
+
+ /** 会话状态 */
+ @Schema(title = "会话状态")
+ @Excel(name = "会话状态")
+ private String status;
+
+ /** 登录时间 */
+ @Schema(title = "登录时间")
+ @Excel(name = "登录时间")
+ private LocalDate loginTime;
+
+ /** 过期时间 */
+ @Schema(title = "过期时间")
+ @Excel(name = "过期时间")
+ private LocalDate expireTime;
+
+ /** 最后活动时间 */
+ @Schema(title = "最后活动时间")
+ @Excel(name = "最后活动时间")
+ private LocalDate lastActivityTime;
+
+ /** 登录IP */
+ @Schema(title = "登录IP")
+ @Excel(name = "登录IP")
+ private String loginIp;
+
+ /** 设备信息 */
+ @Schema(title = "设备信息")
+ @Excel(name = "设备信息")
+ private String deviceInfo;
+
+ /** 浏览器信息 */
+ @Schema(title = "浏览器信息")
+ @Excel(name = "浏览器信息")
+ private String browserInfo;
+
+ /** 会话标识 */
+ @Schema(title = "会话标识")
+ @Excel(name = "会话标识")
+ private String sessionToken;
+
+ /** 令牌ID */
+ @Schema(title = "令牌ID")
+ @Excel(name = "令牌ID")
+ private Long tokenId;
+ public void setSessionId(Long sessionId)
+ {
+ this.sessionId = sessionId;
+ }
+
+ public Long getSessionId()
+ {
+ return sessionId;
+ }
+
+
+ public void setTenantId(String tenantId)
+ {
+ this.tenantId = tenantId;
+ }
+
+ public String getTenantId()
+ {
+ return tenantId;
+ }
+
+
+ public void setUsername(String username)
+ {
+ this.username = username;
+ }
+
+ public String getUsername()
+ {
+ return username;
+ }
+
+
+ public void setLoginType(String loginType)
+ {
+ this.loginType = loginType;
+ }
+
+ public String getLoginType()
+ {
+ return loginType;
+ }
+
+
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+ public String getStatus()
+ {
+ return status;
+ }
+
+
+ public void setLoginTime(LocalDate loginTime)
+ {
+ this.loginTime = loginTime;
+ }
+
+ public LocalDate getLoginTime()
+ {
+ return loginTime;
+ }
+
+
+ public void setExpireTime(LocalDate expireTime)
+ {
+ this.expireTime = expireTime;
+ }
+
+ public LocalDate getExpireTime()
+ {
+ return expireTime;
+ }
+
+
+ public void setLastActivityTime(LocalDate lastActivityTime)
+ {
+ this.lastActivityTime = lastActivityTime;
+ }
+
+ public LocalDate getLastActivityTime()
+ {
+ return lastActivityTime;
+ }
+
+
+ public void setLoginIp(String loginIp)
+ {
+ this.loginIp = loginIp;
+ }
+
+ public String getLoginIp()
+ {
+ return loginIp;
+ }
+
+
+ public void setDeviceInfo(String deviceInfo)
+ {
+ this.deviceInfo = deviceInfo;
+ }
+
+ public String getDeviceInfo()
+ {
+ return deviceInfo;
+ }
+
+
+ public void setBrowserInfo(String browserInfo)
+ {
+ this.browserInfo = browserInfo;
+ }
+
+ public String getBrowserInfo()
+ {
+ return browserInfo;
+ }
+
+
+ public void setSessionToken(String sessionToken)
+ {
+ this.sessionToken = sessionToken;
+ }
+
+ public String getSessionToken()
+ {
+ return sessionToken;
+ }
+
+
+ public void setTokenId(Long tokenId)
+ {
+ this.tokenId = tokenId;
+ }
+
+ public Long getTokenId()
+ {
+ return tokenId;
+ }
+
+
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("sessionId", getSessionId())
+ .append("tenantId", getTenantId())
+ .append("username", getUsername())
+ .append("loginType", getLoginType())
+ .append("status", getStatus())
+ .append("loginTime", getLoginTime())
+ .append("expireTime", getExpireTime())
+ .append("lastActivityTime", getLastActivityTime())
+ .append("loginIp", getLoginIp())
+ .append("deviceInfo", getDeviceInfo())
+ .append("browserInfo", getBrowserInfo())
+ .append("sessionToken", getSessionToken())
+ .append("tokenId", getTokenId())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .toString();
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfLoginStatistics.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfLoginStatistics.java
new file mode 100644
index 00000000..34fb6d76
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfLoginStatistics.java
@@ -0,0 +1,184 @@
+package com.datai.auth.domain;
+
+import java.time.LocalDate;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.datai.common.annotation.Excel;
+import com.datai.common.core.domain.BaseEntity;
+
+/**
+ * 登录统计对象 datai_sf_login_statistics
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@Schema(description = "登录统计对象")
+public class DataiSfLoginStatistics extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+
+ /** 统计ID */
+ @Schema(title = "统计ID")
+ private Long statId;
+
+ /** 租户编号 */
+ @Schema(title = "租户编号")
+ @Excel(name = "租户编号")
+ private String tenantId;
+
+ /** 统计日期 */
+ @Schema(title = "统计日期")
+ @Excel(name = "统计日期")
+ private LocalDate statDate;
+
+ /** 统计小时 */
+ @Schema(title = "统计小时")
+ @Excel(name = "统计小时")
+ private Long statHour;
+
+ /** 登录类型 */
+ @Schema(title = "登录类型")
+ @Excel(name = "登录类型")
+ private String loginType;
+
+ /** 成功次数 */
+ @Schema(title = "成功次数")
+ @Excel(name = "成功次数")
+ private Long successCount;
+
+ /** 失败次数 */
+ @Schema(title = "失败次数")
+ @Excel(name = "失败次数")
+ private Long failedCount;
+
+ /** 刷新次数 */
+ @Schema(title = "刷新次数")
+ @Excel(name = "刷新次数")
+ private Long refreshCount;
+
+ /** 吊销次数 */
+ @Schema(title = "吊销次数")
+ @Excel(name = "吊销次数")
+ private Long revokeCount;
+ public void setStatId(Long statId)
+ {
+ this.statId = statId;
+ }
+
+ public Long getStatId()
+ {
+ return statId;
+ }
+
+
+ public void setTenantId(String tenantId)
+ {
+ this.tenantId = tenantId;
+ }
+
+ public String getTenantId()
+ {
+ return tenantId;
+ }
+
+
+ public void setStatDate(LocalDate statDate)
+ {
+ this.statDate = statDate;
+ }
+
+ public LocalDate getStatDate()
+ {
+ return statDate;
+ }
+
+
+ public void setStatHour(Long statHour)
+ {
+ this.statHour = statHour;
+ }
+
+ public Long getStatHour()
+ {
+ return statHour;
+ }
+
+
+ public void setLoginType(String loginType)
+ {
+ this.loginType = loginType;
+ }
+
+ public String getLoginType()
+ {
+ return loginType;
+ }
+
+
+ public void setSuccessCount(Long successCount)
+ {
+ this.successCount = successCount;
+ }
+
+ public Long getSuccessCount()
+ {
+ return successCount;
+ }
+
+
+ public void setFailedCount(Long failedCount)
+ {
+ this.failedCount = failedCount;
+ }
+
+ public Long getFailedCount()
+ {
+ return failedCount;
+ }
+
+
+ public void setRefreshCount(Long refreshCount)
+ {
+ this.refreshCount = refreshCount;
+ }
+
+ public Long getRefreshCount()
+ {
+ return refreshCount;
+ }
+
+
+ public void setRevokeCount(Long revokeCount)
+ {
+ this.revokeCount = revokeCount;
+ }
+
+ public Long getRevokeCount()
+ {
+ return revokeCount;
+ }
+
+
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("statId", getStatId())
+ .append("tenantId", getTenantId())
+ .append("statDate", getStatDate())
+ .append("statHour", getStatHour())
+ .append("loginType", getLoginType())
+ .append("successCount", getSuccessCount())
+ .append("failedCount", getFailedCount())
+ .append("refreshCount", getRefreshCount())
+ .append("revokeCount", getRevokeCount())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .toString();
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfToken.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfToken.java
new file mode 100644
index 00000000..07859a5a
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfToken.java
@@ -0,0 +1,286 @@
+package com.datai.auth.domain;
+
+import java.time.LocalDate;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.datai.common.annotation.Excel;
+import com.datai.common.core.domain.BaseEntity;
+
+/**
+ * 令牌对象 datai_sf_token
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@Schema(description = "令牌对象")
+public class DataiSfToken extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+
+ /** 令牌ID */
+ @Schema(title = "令牌ID")
+ private Long tokenId;
+
+ /** 租户编号 */
+ @Schema(title = "租户编号")
+ @Excel(name = "租户编号")
+ private String tenantId;
+
+ /** 用户名 */
+ @Schema(title = "用户名")
+ @Excel(name = "用户名")
+ private String username;
+
+ /** 访问令牌 */
+ @Schema(title = "访问令牌")
+ @Excel(name = "访问令牌")
+ private String accessToken;
+
+ /** 刷新令牌 */
+ @Schema(title = "刷新令牌")
+ @Excel(name = "刷新令牌")
+ private String refreshToken;
+
+ /** 访问令牌过期时间 */
+ @Schema(title = "访问令牌过期时间")
+ @Excel(name = "访问令牌过期时间")
+ private LocalDate accessTokenExpire;
+
+ /** 刷新令牌过期时间 */
+ @Schema(title = "刷新令牌过期时间")
+ @Excel(name = "刷新令牌过期时间")
+ private LocalDate refreshTokenExpire;
+
+ /** 令牌状态 */
+ @Schema(title = "令牌状态")
+ @Excel(name = "令牌状态")
+ private String status;
+
+ /** 实例URL */
+ @Schema(title = "实例URL")
+ @Excel(name = "实例URL")
+ private String instanceUrl;
+
+ /** 登录类型 */
+ @Schema(title = "登录类型")
+ @Excel(name = "登录类型")
+ private String loginType;
+
+ /** 客户端ID */
+ @Schema(title = "客户端ID")
+ @Excel(name = "客户端ID")
+ private String clientId;
+
+ /** 作用域 */
+ @Schema(title = "作用域")
+ @Excel(name = "作用域")
+ private String scope;
+
+ /** 令牌类型 */
+ @Schema(title = "令牌类型")
+ @Excel(name = "令牌类型")
+ private String tokenType;
+
+ /** 组织ID */
+ @Schema(title = "组织ID")
+ @Excel(name = "组织ID")
+ private String organizationId;
+
+ /** 用户ID */
+ @Schema(title = "用户ID")
+ @Excel(name = "用户ID")
+ private String userId;
+ public void setTokenId(Long tokenId)
+ {
+ this.tokenId = tokenId;
+ }
+
+ public Long getTokenId()
+ {
+ return tokenId;
+ }
+
+
+ public void setTenantId(String tenantId)
+ {
+ this.tenantId = tenantId;
+ }
+
+ public String getTenantId()
+ {
+ return tenantId;
+ }
+
+
+ public void setUsername(String username)
+ {
+ this.username = username;
+ }
+
+ public String getUsername()
+ {
+ return username;
+ }
+
+
+ public void setAccessToken(String accessToken)
+ {
+ this.accessToken = accessToken;
+ }
+
+ public String getAccessToken()
+ {
+ return accessToken;
+ }
+
+
+ public void setRefreshToken(String refreshToken)
+ {
+ this.refreshToken = refreshToken;
+ }
+
+ public String getRefreshToken()
+ {
+ return refreshToken;
+ }
+
+
+ public void setAccessTokenExpire(LocalDate accessTokenExpire)
+ {
+ this.accessTokenExpire = accessTokenExpire;
+ }
+
+ public LocalDate getAccessTokenExpire()
+ {
+ return accessTokenExpire;
+ }
+
+
+ public void setRefreshTokenExpire(LocalDate refreshTokenExpire)
+ {
+ this.refreshTokenExpire = refreshTokenExpire;
+ }
+
+ public LocalDate getRefreshTokenExpire()
+ {
+ return refreshTokenExpire;
+ }
+
+
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+ public String getStatus()
+ {
+ return status;
+ }
+
+
+ public void setInstanceUrl(String instanceUrl)
+ {
+ this.instanceUrl = instanceUrl;
+ }
+
+ public String getInstanceUrl()
+ {
+ return instanceUrl;
+ }
+
+
+ public void setLoginType(String loginType)
+ {
+ this.loginType = loginType;
+ }
+
+ public String getLoginType()
+ {
+ return loginType;
+ }
+
+
+ public void setClientId(String clientId)
+ {
+ this.clientId = clientId;
+ }
+
+ public String getClientId()
+ {
+ return clientId;
+ }
+
+
+ public void setScope(String scope)
+ {
+ this.scope = scope;
+ }
+
+ public String getScope()
+ {
+ return scope;
+ }
+
+
+ public void setTokenType(String tokenType)
+ {
+ this.tokenType = tokenType;
+ }
+
+ public String getTokenType()
+ {
+ return tokenType;
+ }
+
+
+ public void setOrganizationId(String organizationId)
+ {
+ this.organizationId = organizationId;
+ }
+
+ public String getOrganizationId()
+ {
+ return organizationId;
+ }
+
+
+ public void setUserId(String userId)
+ {
+ this.userId = userId;
+ }
+
+ public String getUserId()
+ {
+ return userId;
+ }
+
+
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("tokenId", getTokenId())
+ .append("tenantId", getTenantId())
+ .append("username", getUsername())
+ .append("accessToken", getAccessToken())
+ .append("refreshToken", getRefreshToken())
+ .append("accessTokenExpire", getAccessTokenExpire())
+ .append("refreshTokenExpire", getRefreshTokenExpire())
+ .append("status", getStatus())
+ .append("instanceUrl", getInstanceUrl())
+ .append("loginType", getLoginType())
+ .append("clientId", getClientId())
+ .append("scope", getScope())
+ .append("tokenType", getTokenType())
+ .append("organizationId", getOrganizationId())
+ .append("userId", getUserId())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .toString();
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfTokenBinding.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfTokenBinding.java
new file mode 100644
index 00000000..5e1993bf
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/domain/DataiSfTokenBinding.java
@@ -0,0 +1,184 @@
+package com.datai.auth.domain;
+
+import java.time.LocalDate;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.datai.common.annotation.Excel;
+import com.datai.common.core.domain.BaseEntity;
+
+/**
+ * 令牌绑定对象 datai_sf_token_binding
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@Schema(description = "令牌绑定对象")
+public class DataiSfTokenBinding extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+
+ /** 绑定ID */
+ @Schema(title = "绑定ID")
+ private Long bindingId;
+
+ /** 租户编号 */
+ @Schema(title = "租户编号")
+ @Excel(name = "租户编号")
+ private String tenantId;
+
+ /** 令牌ID */
+ @Schema(title = "令牌ID")
+ @Excel(name = "令牌ID")
+ private Long tokenId;
+
+ /** 绑定类型 */
+ @Schema(title = "绑定类型")
+ @Excel(name = "绑定类型")
+ private String bindingType;
+
+ /** 设备ID */
+ @Schema(title = "设备ID")
+ @Excel(name = "设备ID")
+ private String deviceId;
+
+ /** 绑定IP */
+ @Schema(title = "绑定IP")
+ @Excel(name = "绑定IP")
+ private String bindingIp;
+
+ /** 绑定状态 */
+ @Schema(title = "绑定状态")
+ @Excel(name = "绑定状态")
+ private String status;
+
+ /** 绑定时间 */
+ @Schema(title = "绑定时间")
+ @Excel(name = "绑定时间")
+ private LocalDate bindingTime;
+
+ /** 过期时间 */
+ @Schema(title = "过期时间")
+ @Excel(name = "过期时间")
+ private LocalDate expireTime;
+ public void setBindingId(Long bindingId)
+ {
+ this.bindingId = bindingId;
+ }
+
+ public Long getBindingId()
+ {
+ return bindingId;
+ }
+
+
+ public void setTenantId(String tenantId)
+ {
+ this.tenantId = tenantId;
+ }
+
+ public String getTenantId()
+ {
+ return tenantId;
+ }
+
+
+ public void setTokenId(Long tokenId)
+ {
+ this.tokenId = tokenId;
+ }
+
+ public Long getTokenId()
+ {
+ return tokenId;
+ }
+
+
+ public void setBindingType(String bindingType)
+ {
+ this.bindingType = bindingType;
+ }
+
+ public String getBindingType()
+ {
+ return bindingType;
+ }
+
+
+ public void setDeviceId(String deviceId)
+ {
+ this.deviceId = deviceId;
+ }
+
+ public String getDeviceId()
+ {
+ return deviceId;
+ }
+
+
+ public void setBindingIp(String bindingIp)
+ {
+ this.bindingIp = bindingIp;
+ }
+
+ public String getBindingIp()
+ {
+ return bindingIp;
+ }
+
+
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+ public String getStatus()
+ {
+ return status;
+ }
+
+
+ public void setBindingTime(LocalDate bindingTime)
+ {
+ this.bindingTime = bindingTime;
+ }
+
+ public LocalDate getBindingTime()
+ {
+ return bindingTime;
+ }
+
+
+ public void setExpireTime(LocalDate expireTime)
+ {
+ this.expireTime = expireTime;
+ }
+
+ public LocalDate getExpireTime()
+ {
+ return expireTime;
+ }
+
+
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("bindingId", getBindingId())
+ .append("tenantId", getTenantId())
+ .append("tokenId", getTokenId())
+ .append("bindingType", getBindingType())
+ .append("deviceId", getDeviceId())
+ .append("bindingIp", getBindingIp())
+ .append("status", getStatus())
+ .append("bindingTime", getBindingTime())
+ .append("expireTime", getExpireTime())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .toString();
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfFailedLoginMapper.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfFailedLoginMapper.java
new file mode 100644
index 00000000..111bcb12
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfFailedLoginMapper.java
@@ -0,0 +1,61 @@
+package com.datai.auth.mapper;
+
+import java.util.List;
+import com.datai.auth.domain.DataiSfFailedLogin;
+
+/**
+ * 失败登录Mapper接口
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+public interface DataiSfFailedLoginMapper
+{
+ /**
+ * 查询失败登录
+ *
+ * @param failedId 失败登录主键
+ * @return 失败登录
+ */
+ public DataiSfFailedLogin selectDataiSfFailedLoginByFailedId(Long failedId);
+
+ /**
+ * 查询失败登录列表
+ *
+ * @param dataiSfFailedLogin 失败登录
+ * @return 失败登录集合
+ */
+ public List selectDataiSfFailedLoginList(DataiSfFailedLogin dataiSfFailedLogin);
+
+ /**
+ * 新增失败登录
+ *
+ * @param dataiSfFailedLogin 失败登录
+ * @return 结果
+ */
+ public int insertDataiSfFailedLogin(DataiSfFailedLogin dataiSfFailedLogin);
+
+ /**
+ * 修改失败登录
+ *
+ * @param dataiSfFailedLogin 失败登录
+ * @return 结果
+ */
+ public int updateDataiSfFailedLogin(DataiSfFailedLogin dataiSfFailedLogin);
+
+ /**
+ * 删除失败登录
+ *
+ * @param failedId 失败登录主键
+ * @return 结果
+ */
+ public int deleteDataiSfFailedLoginByFailedId(Long failedId);
+
+ /**
+ * 批量删除失败登录
+ *
+ * @param failedIds 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int deleteDataiSfFailedLoginByFailedIds(Long[] failedIds);
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfLoginAuditMapper.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfLoginAuditMapper.java
new file mode 100644
index 00000000..7d91cab4
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfLoginAuditMapper.java
@@ -0,0 +1,61 @@
+package com.datai.auth.mapper;
+
+import java.util.List;
+import com.datai.auth.domain.DataiSfLoginAudit;
+
+/**
+ * 登录审计日志Mapper接口
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+public interface DataiSfLoginAuditMapper
+{
+ /**
+ * 查询登录审计日志
+ *
+ * @param auditId 登录审计日志主键
+ * @return 登录审计日志
+ */
+ public DataiSfLoginAudit selectDataiSfLoginAuditByAuditId(Long auditId);
+
+ /**
+ * 查询登录审计日志列表
+ *
+ * @param dataiSfLoginAudit 登录审计日志
+ * @return 登录审计日志集合
+ */
+ public List selectDataiSfLoginAuditList(DataiSfLoginAudit dataiSfLoginAudit);
+
+ /**
+ * 新增登录审计日志
+ *
+ * @param dataiSfLoginAudit 登录审计日志
+ * @return 结果
+ */
+ public int insertDataiSfLoginAudit(DataiSfLoginAudit dataiSfLoginAudit);
+
+ /**
+ * 修改登录审计日志
+ *
+ * @param dataiSfLoginAudit 登录审计日志
+ * @return 结果
+ */
+ public int updateDataiSfLoginAudit(DataiSfLoginAudit dataiSfLoginAudit);
+
+ /**
+ * 删除登录审计日志
+ *
+ * @param auditId 登录审计日志主键
+ * @return 结果
+ */
+ public int deleteDataiSfLoginAuditByAuditId(Long auditId);
+
+ /**
+ * 批量删除登录审计日志
+ *
+ * @param auditIds 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int deleteDataiSfLoginAuditByAuditIds(Long[] auditIds);
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfLoginSessionMapper.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfLoginSessionMapper.java
new file mode 100644
index 00000000..6435e841
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfLoginSessionMapper.java
@@ -0,0 +1,61 @@
+package com.datai.auth.mapper;
+
+import java.util.List;
+import com.datai.auth.domain.DataiSfLoginSession;
+
+/**
+ * 登录会话Mapper接口
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+public interface DataiSfLoginSessionMapper
+{
+ /**
+ * 查询登录会话
+ *
+ * @param sessionId 登录会话主键
+ * @return 登录会话
+ */
+ public DataiSfLoginSession selectDataiSfLoginSessionBySessionId(Long sessionId);
+
+ /**
+ * 查询登录会话列表
+ *
+ * @param dataiSfLoginSession 登录会话
+ * @return 登录会话集合
+ */
+ public List selectDataiSfLoginSessionList(DataiSfLoginSession dataiSfLoginSession);
+
+ /**
+ * 新增登录会话
+ *
+ * @param dataiSfLoginSession 登录会话
+ * @return 结果
+ */
+ public int insertDataiSfLoginSession(DataiSfLoginSession dataiSfLoginSession);
+
+ /**
+ * 修改登录会话
+ *
+ * @param dataiSfLoginSession 登录会话
+ * @return 结果
+ */
+ public int updateDataiSfLoginSession(DataiSfLoginSession dataiSfLoginSession);
+
+ /**
+ * 删除登录会话
+ *
+ * @param sessionId 登录会话主键
+ * @return 结果
+ */
+ public int deleteDataiSfLoginSessionBySessionId(Long sessionId);
+
+ /**
+ * 批量删除登录会话
+ *
+ * @param sessionIds 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int deleteDataiSfLoginSessionBySessionIds(Long[] sessionIds);
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfLoginStatisticsMapper.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfLoginStatisticsMapper.java
new file mode 100644
index 00000000..50adbc5e
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfLoginStatisticsMapper.java
@@ -0,0 +1,61 @@
+package com.datai.auth.mapper;
+
+import java.util.List;
+import com.datai.auth.domain.DataiSfLoginStatistics;
+
+/**
+ * 登录统计Mapper接口
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+public interface DataiSfLoginStatisticsMapper
+{
+ /**
+ * 查询登录统计
+ *
+ * @param statId 登录统计主键
+ * @return 登录统计
+ */
+ public DataiSfLoginStatistics selectDataiSfLoginStatisticsByStatId(Long statId);
+
+ /**
+ * 查询登录统计列表
+ *
+ * @param dataiSfLoginStatistics 登录统计
+ * @return 登录统计集合
+ */
+ public List selectDataiSfLoginStatisticsList(DataiSfLoginStatistics dataiSfLoginStatistics);
+
+ /**
+ * 新增登录统计
+ *
+ * @param dataiSfLoginStatistics 登录统计
+ * @return 结果
+ */
+ public int insertDataiSfLoginStatistics(DataiSfLoginStatistics dataiSfLoginStatistics);
+
+ /**
+ * 修改登录统计
+ *
+ * @param dataiSfLoginStatistics 登录统计
+ * @return 结果
+ */
+ public int updateDataiSfLoginStatistics(DataiSfLoginStatistics dataiSfLoginStatistics);
+
+ /**
+ * 删除登录统计
+ *
+ * @param statId 登录统计主键
+ * @return 结果
+ */
+ public int deleteDataiSfLoginStatisticsByStatId(Long statId);
+
+ /**
+ * 批量删除登录统计
+ *
+ * @param statIds 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int deleteDataiSfLoginStatisticsByStatIds(Long[] statIds);
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfTokenBindingMapper.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfTokenBindingMapper.java
new file mode 100644
index 00000000..132d8ed9
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfTokenBindingMapper.java
@@ -0,0 +1,61 @@
+package com.datai.auth.mapper;
+
+import java.util.List;
+import com.datai.auth.domain.DataiSfTokenBinding;
+
+/**
+ * 令牌绑定Mapper接口
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+public interface DataiSfTokenBindingMapper
+{
+ /**
+ * 查询令牌绑定
+ *
+ * @param bindingId 令牌绑定主键
+ * @return 令牌绑定
+ */
+ public DataiSfTokenBinding selectDataiSfTokenBindingByBindingId(Long bindingId);
+
+ /**
+ * 查询令牌绑定列表
+ *
+ * @param dataiSfTokenBinding 令牌绑定
+ * @return 令牌绑定集合
+ */
+ public List selectDataiSfTokenBindingList(DataiSfTokenBinding dataiSfTokenBinding);
+
+ /**
+ * 新增令牌绑定
+ *
+ * @param dataiSfTokenBinding 令牌绑定
+ * @return 结果
+ */
+ public int insertDataiSfTokenBinding(DataiSfTokenBinding dataiSfTokenBinding);
+
+ /**
+ * 修改令牌绑定
+ *
+ * @param dataiSfTokenBinding 令牌绑定
+ * @return 结果
+ */
+ public int updateDataiSfTokenBinding(DataiSfTokenBinding dataiSfTokenBinding);
+
+ /**
+ * 删除令牌绑定
+ *
+ * @param bindingId 令牌绑定主键
+ * @return 结果
+ */
+ public int deleteDataiSfTokenBindingByBindingId(Long bindingId);
+
+ /**
+ * 批量删除令牌绑定
+ *
+ * @param bindingIds 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int deleteDataiSfTokenBindingByBindingIds(Long[] bindingIds);
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfTokenMapper.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfTokenMapper.java
new file mode 100644
index 00000000..13e50827
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/mapper/DataiSfTokenMapper.java
@@ -0,0 +1,61 @@
+package com.datai.auth.mapper;
+
+import java.util.List;
+import com.datai.auth.domain.DataiSfToken;
+
+/**
+ * 令牌Mapper接口
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+public interface DataiSfTokenMapper
+{
+ /**
+ * 查询令牌
+ *
+ * @param tokenId 令牌主键
+ * @return 令牌
+ */
+ public DataiSfToken selectDataiSfTokenByTokenId(Long tokenId);
+
+ /**
+ * 查询令牌列表
+ *
+ * @param dataiSfToken 令牌
+ * @return 令牌集合
+ */
+ public List selectDataiSfTokenList(DataiSfToken dataiSfToken);
+
+ /**
+ * 新增令牌
+ *
+ * @param dataiSfToken 令牌
+ * @return 结果
+ */
+ public int insertDataiSfToken(DataiSfToken dataiSfToken);
+
+ /**
+ * 修改令牌
+ *
+ * @param dataiSfToken 令牌
+ * @return 结果
+ */
+ public int updateDataiSfToken(DataiSfToken dataiSfToken);
+
+ /**
+ * 删除令牌
+ *
+ * @param tokenId 令牌主键
+ * @return 结果
+ */
+ public int deleteDataiSfTokenByTokenId(Long tokenId);
+
+ /**
+ * 批量删除令牌
+ *
+ * @param tokenIds 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int deleteDataiSfTokenByTokenIds(Long[] tokenIds);
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfFailedLoginService.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfFailedLoginService.java
new file mode 100644
index 00000000..6115dab7
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfFailedLoginService.java
@@ -0,0 +1,61 @@
+package com.datai.auth.service;
+
+import java.util.List;
+import com.datai.auth.domain.DataiSfFailedLogin;
+
+/**
+ * 失败登录Service接口
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+public interface IDataiSfFailedLoginService
+{
+ /**
+ * 查询失败登录
+ *
+ * @param failedId 失败登录主键
+ * @return 失败登录
+ */
+ public DataiSfFailedLogin selectDataiSfFailedLoginByFailedId(Long failedId);
+
+ /**
+ * 查询失败登录列表
+ *
+ * @param dataiSfFailedLogin 失败登录
+ * @return 失败登录集合
+ */
+ public List selectDataiSfFailedLoginList(DataiSfFailedLogin dataiSfFailedLogin);
+
+ /**
+ * 新增失败登录
+ *
+ * @param dataiSfFailedLogin 失败登录
+ * @return 结果
+ */
+ public int insertDataiSfFailedLogin(DataiSfFailedLogin dataiSfFailedLogin);
+
+ /**
+ * 修改失败登录
+ *
+ * @param dataiSfFailedLogin 失败登录
+ * @return 结果
+ */
+ public int updateDataiSfFailedLogin(DataiSfFailedLogin dataiSfFailedLogin);
+
+ /**
+ * 批量删除失败登录
+ *
+ * @param failedIds 需要删除的失败登录主键集合
+ * @return 结果
+ */
+ public int deleteDataiSfFailedLoginByFailedIds(Long[] failedIds);
+
+ /**
+ * 删除失败登录信息
+ *
+ * @param failedId 失败登录主键
+ * @return 结果
+ */
+ public int deleteDataiSfFailedLoginByFailedId(Long failedId);
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfLoginAuditService.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfLoginAuditService.java
new file mode 100644
index 00000000..ba1862b0
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfLoginAuditService.java
@@ -0,0 +1,61 @@
+package com.datai.auth.service;
+
+import java.util.List;
+import com.datai.auth.domain.DataiSfLoginAudit;
+
+/**
+ * 登录审计日志Service接口
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+public interface IDataiSfLoginAuditService
+{
+ /**
+ * 查询登录审计日志
+ *
+ * @param auditId 登录审计日志主键
+ * @return 登录审计日志
+ */
+ public DataiSfLoginAudit selectDataiSfLoginAuditByAuditId(Long auditId);
+
+ /**
+ * 查询登录审计日志列表
+ *
+ * @param dataiSfLoginAudit 登录审计日志
+ * @return 登录审计日志集合
+ */
+ public List selectDataiSfLoginAuditList(DataiSfLoginAudit dataiSfLoginAudit);
+
+ /**
+ * 新增登录审计日志
+ *
+ * @param dataiSfLoginAudit 登录审计日志
+ * @return 结果
+ */
+ public int insertDataiSfLoginAudit(DataiSfLoginAudit dataiSfLoginAudit);
+
+ /**
+ * 修改登录审计日志
+ *
+ * @param dataiSfLoginAudit 登录审计日志
+ * @return 结果
+ */
+ public int updateDataiSfLoginAudit(DataiSfLoginAudit dataiSfLoginAudit);
+
+ /**
+ * 批量删除登录审计日志
+ *
+ * @param auditIds 需要删除的登录审计日志主键集合
+ * @return 结果
+ */
+ public int deleteDataiSfLoginAuditByAuditIds(Long[] auditIds);
+
+ /**
+ * 删除登录审计日志信息
+ *
+ * @param auditId 登录审计日志主键
+ * @return 结果
+ */
+ public int deleteDataiSfLoginAuditByAuditId(Long auditId);
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfLoginSessionService.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfLoginSessionService.java
new file mode 100644
index 00000000..57079337
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfLoginSessionService.java
@@ -0,0 +1,61 @@
+package com.datai.auth.service;
+
+import java.util.List;
+import com.datai.auth.domain.DataiSfLoginSession;
+
+/**
+ * 登录会话Service接口
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+public interface IDataiSfLoginSessionService
+{
+ /**
+ * 查询登录会话
+ *
+ * @param sessionId 登录会话主键
+ * @return 登录会话
+ */
+ public DataiSfLoginSession selectDataiSfLoginSessionBySessionId(Long sessionId);
+
+ /**
+ * 查询登录会话列表
+ *
+ * @param dataiSfLoginSession 登录会话
+ * @return 登录会话集合
+ */
+ public List selectDataiSfLoginSessionList(DataiSfLoginSession dataiSfLoginSession);
+
+ /**
+ * 新增登录会话
+ *
+ * @param dataiSfLoginSession 登录会话
+ * @return 结果
+ */
+ public int insertDataiSfLoginSession(DataiSfLoginSession dataiSfLoginSession);
+
+ /**
+ * 修改登录会话
+ *
+ * @param dataiSfLoginSession 登录会话
+ * @return 结果
+ */
+ public int updateDataiSfLoginSession(DataiSfLoginSession dataiSfLoginSession);
+
+ /**
+ * 批量删除登录会话
+ *
+ * @param sessionIds 需要删除的登录会话主键集合
+ * @return 结果
+ */
+ public int deleteDataiSfLoginSessionBySessionIds(Long[] sessionIds);
+
+ /**
+ * 删除登录会话信息
+ *
+ * @param sessionId 登录会话主键
+ * @return 结果
+ */
+ public int deleteDataiSfLoginSessionBySessionId(Long sessionId);
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfLoginStatisticsService.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfLoginStatisticsService.java
new file mode 100644
index 00000000..c8f77e76
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfLoginStatisticsService.java
@@ -0,0 +1,61 @@
+package com.datai.auth.service;
+
+import java.util.List;
+import com.datai.auth.domain.DataiSfLoginStatistics;
+
+/**
+ * 登录统计Service接口
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+public interface IDataiSfLoginStatisticsService
+{
+ /**
+ * 查询登录统计
+ *
+ * @param statId 登录统计主键
+ * @return 登录统计
+ */
+ public DataiSfLoginStatistics selectDataiSfLoginStatisticsByStatId(Long statId);
+
+ /**
+ * 查询登录统计列表
+ *
+ * @param dataiSfLoginStatistics 登录统计
+ * @return 登录统计集合
+ */
+ public List selectDataiSfLoginStatisticsList(DataiSfLoginStatistics dataiSfLoginStatistics);
+
+ /**
+ * 新增登录统计
+ *
+ * @param dataiSfLoginStatistics 登录统计
+ * @return 结果
+ */
+ public int insertDataiSfLoginStatistics(DataiSfLoginStatistics dataiSfLoginStatistics);
+
+ /**
+ * 修改登录统计
+ *
+ * @param dataiSfLoginStatistics 登录统计
+ * @return 结果
+ */
+ public int updateDataiSfLoginStatistics(DataiSfLoginStatistics dataiSfLoginStatistics);
+
+ /**
+ * 批量删除登录统计
+ *
+ * @param statIds 需要删除的登录统计主键集合
+ * @return 结果
+ */
+ public int deleteDataiSfLoginStatisticsByStatIds(Long[] statIds);
+
+ /**
+ * 删除登录统计信息
+ *
+ * @param statId 登录统计主键
+ * @return 结果
+ */
+ public int deleteDataiSfLoginStatisticsByStatId(Long statId);
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfTokenBindingService.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfTokenBindingService.java
new file mode 100644
index 00000000..d7596296
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfTokenBindingService.java
@@ -0,0 +1,61 @@
+package com.datai.auth.service;
+
+import java.util.List;
+import com.datai.auth.domain.DataiSfTokenBinding;
+
+/**
+ * 令牌绑定Service接口
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+public interface IDataiSfTokenBindingService
+{
+ /**
+ * 查询令牌绑定
+ *
+ * @param bindingId 令牌绑定主键
+ * @return 令牌绑定
+ */
+ public DataiSfTokenBinding selectDataiSfTokenBindingByBindingId(Long bindingId);
+
+ /**
+ * 查询令牌绑定列表
+ *
+ * @param dataiSfTokenBinding 令牌绑定
+ * @return 令牌绑定集合
+ */
+ public List selectDataiSfTokenBindingList(DataiSfTokenBinding dataiSfTokenBinding);
+
+ /**
+ * 新增令牌绑定
+ *
+ * @param dataiSfTokenBinding 令牌绑定
+ * @return 结果
+ */
+ public int insertDataiSfTokenBinding(DataiSfTokenBinding dataiSfTokenBinding);
+
+ /**
+ * 修改令牌绑定
+ *
+ * @param dataiSfTokenBinding 令牌绑定
+ * @return 结果
+ */
+ public int updateDataiSfTokenBinding(DataiSfTokenBinding dataiSfTokenBinding);
+
+ /**
+ * 批量删除令牌绑定
+ *
+ * @param bindingIds 需要删除的令牌绑定主键集合
+ * @return 结果
+ */
+ public int deleteDataiSfTokenBindingByBindingIds(Long[] bindingIds);
+
+ /**
+ * 删除令牌绑定信息
+ *
+ * @param bindingId 令牌绑定主键
+ * @return 结果
+ */
+ public int deleteDataiSfTokenBindingByBindingId(Long bindingId);
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfTokenService.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfTokenService.java
new file mode 100644
index 00000000..6a0f5a63
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/IDataiSfTokenService.java
@@ -0,0 +1,61 @@
+package com.datai.auth.service;
+
+import java.util.List;
+import com.datai.auth.domain.DataiSfToken;
+
+/**
+ * 令牌Service接口
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+public interface IDataiSfTokenService
+{
+ /**
+ * 查询令牌
+ *
+ * @param tokenId 令牌主键
+ * @return 令牌
+ */
+ public DataiSfToken selectDataiSfTokenByTokenId(Long tokenId);
+
+ /**
+ * 查询令牌列表
+ *
+ * @param dataiSfToken 令牌
+ * @return 令牌集合
+ */
+ public List selectDataiSfTokenList(DataiSfToken dataiSfToken);
+
+ /**
+ * 新增令牌
+ *
+ * @param dataiSfToken 令牌
+ * @return 结果
+ */
+ public int insertDataiSfToken(DataiSfToken dataiSfToken);
+
+ /**
+ * 修改令牌
+ *
+ * @param dataiSfToken 令牌
+ * @return 结果
+ */
+ public int updateDataiSfToken(DataiSfToken dataiSfToken);
+
+ /**
+ * 批量删除令牌
+ *
+ * @param tokenIds 需要删除的令牌主键集合
+ * @return 结果
+ */
+ public int deleteDataiSfTokenByTokenIds(Long[] tokenIds);
+
+ /**
+ * 删除令牌信息
+ *
+ * @param tokenId 令牌主键
+ * @return 结果
+ */
+ public int deleteDataiSfTokenByTokenId(Long tokenId);
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfFailedLoginServiceImpl.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfFailedLoginServiceImpl.java
new file mode 100644
index 00000000..c868f70d
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfFailedLoginServiceImpl.java
@@ -0,0 +1,107 @@
+package com.datai.auth.service.impl;
+
+import java.util.List;
+
+import com.datai.common.core.domain.model.LoginUser;
+import com.datai.common.utils.DateUtils;
+ import com.datai.common.utils.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.datai.auth.mapper.DataiSfFailedLoginMapper;
+import com.datai.auth.domain.DataiSfFailedLogin;
+import com.datai.auth.service.IDataiSfFailedLoginService;
+
+
+/**
+ * 失败登录Service业务层处理
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@Service
+public class DataiSfFailedLoginServiceImpl implements IDataiSfFailedLoginService {
+ @Autowired
+ private DataiSfFailedLoginMapper dataiSfFailedLoginMapper;
+
+ /**
+ * 查询失败登录
+ *
+ * @param failedId 失败登录主键
+ * @return 失败登录
+ */
+ @Override
+ public DataiSfFailedLogin selectDataiSfFailedLoginByFailedId(Long failedId)
+ {
+ return dataiSfFailedLoginMapper.selectDataiSfFailedLoginByFailedId(failedId);
+ }
+
+ /**
+ * 查询失败登录列表
+ *
+ * @param dataiSfFailedLogin 失败登录
+ * @return 失败登录
+ */
+ @Override
+ public List selectDataiSfFailedLoginList(DataiSfFailedLogin dataiSfFailedLogin)
+ {
+ return dataiSfFailedLoginMapper.selectDataiSfFailedLoginList(dataiSfFailedLogin);
+ }
+
+ /**
+ * 新增失败登录
+ *
+ * @param dataiSfFailedLogin 失败登录
+ * @return 结果
+ */
+ @Override
+ public int insertDataiSfFailedLogin(DataiSfFailedLogin dataiSfFailedLogin)
+ {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ String username = loginUser.getUsername();
+
+ dataiSfFailedLogin.setCreateTime(DateUtils.getNowDate());
+ dataiSfFailedLogin.setUpdateTime(DateUtils.getNowDate());
+ dataiSfFailedLogin.setCreateBy(username);
+ dataiSfFailedLogin.setUpdateBy(username);
+ return dataiSfFailedLoginMapper.insertDataiSfFailedLogin(dataiSfFailedLogin);
+ }
+
+ /**
+ * 修改失败登录
+ *
+ * @param dataiSfFailedLogin 失败登录
+ * @return 结果
+ */
+ @Override
+ public int updateDataiSfFailedLogin(DataiSfFailedLogin dataiSfFailedLogin)
+ {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ String username = loginUser.getUsername();
+
+ return dataiSfFailedLoginMapper.updateDataiSfFailedLogin(dataiSfFailedLogin);
+ }
+
+ /**
+ * 批量删除失败登录
+ *
+ * @param failedIds 需要删除的失败登录主键
+ * @return 结果
+ */
+ @Override
+ public int deleteDataiSfFailedLoginByFailedIds(Long[] failedIds)
+ {
+ return dataiSfFailedLoginMapper.deleteDataiSfFailedLoginByFailedIds(failedIds);
+ }
+
+ /**
+ * 删除失败登录信息
+ *
+ * @param failedId 失败登录主键
+ * @return 结果
+ */
+ @Override
+ public int deleteDataiSfFailedLoginByFailedId(Long failedId)
+ {
+ return dataiSfFailedLoginMapper.deleteDataiSfFailedLoginByFailedId(failedId);
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfLoginAuditServiceImpl.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfLoginAuditServiceImpl.java
new file mode 100644
index 00000000..2e8727e5
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfLoginAuditServiceImpl.java
@@ -0,0 +1,107 @@
+package com.datai.auth.service.impl;
+
+import java.util.List;
+
+import com.datai.common.core.domain.model.LoginUser;
+import com.datai.common.utils.DateUtils;
+ import com.datai.common.utils.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.datai.auth.mapper.DataiSfLoginAuditMapper;
+import com.datai.auth.domain.DataiSfLoginAudit;
+import com.datai.auth.service.IDataiSfLoginAuditService;
+
+
+/**
+ * 登录审计日志Service业务层处理
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@Service
+public class DataiSfLoginAuditServiceImpl implements IDataiSfLoginAuditService {
+ @Autowired
+ private DataiSfLoginAuditMapper dataiSfLoginAuditMapper;
+
+ /**
+ * 查询登录审计日志
+ *
+ * @param auditId 登录审计日志主键
+ * @return 登录审计日志
+ */
+ @Override
+ public DataiSfLoginAudit selectDataiSfLoginAuditByAuditId(Long auditId)
+ {
+ return dataiSfLoginAuditMapper.selectDataiSfLoginAuditByAuditId(auditId);
+ }
+
+ /**
+ * 查询登录审计日志列表
+ *
+ * @param dataiSfLoginAudit 登录审计日志
+ * @return 登录审计日志
+ */
+ @Override
+ public List selectDataiSfLoginAuditList(DataiSfLoginAudit dataiSfLoginAudit)
+ {
+ return dataiSfLoginAuditMapper.selectDataiSfLoginAuditList(dataiSfLoginAudit);
+ }
+
+ /**
+ * 新增登录审计日志
+ *
+ * @param dataiSfLoginAudit 登录审计日志
+ * @return 结果
+ */
+ @Override
+ public int insertDataiSfLoginAudit(DataiSfLoginAudit dataiSfLoginAudit)
+ {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ String username = loginUser.getUsername();
+
+ dataiSfLoginAudit.setCreateTime(DateUtils.getNowDate());
+ dataiSfLoginAudit.setUpdateTime(DateUtils.getNowDate());
+ dataiSfLoginAudit.setCreateBy(username);
+ dataiSfLoginAudit.setUpdateBy(username);
+ return dataiSfLoginAuditMapper.insertDataiSfLoginAudit(dataiSfLoginAudit);
+ }
+
+ /**
+ * 修改登录审计日志
+ *
+ * @param dataiSfLoginAudit 登录审计日志
+ * @return 结果
+ */
+ @Override
+ public int updateDataiSfLoginAudit(DataiSfLoginAudit dataiSfLoginAudit)
+ {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ String username = loginUser.getUsername();
+
+ return dataiSfLoginAuditMapper.updateDataiSfLoginAudit(dataiSfLoginAudit);
+ }
+
+ /**
+ * 批量删除登录审计日志
+ *
+ * @param auditIds 需要删除的登录审计日志主键
+ * @return 结果
+ */
+ @Override
+ public int deleteDataiSfLoginAuditByAuditIds(Long[] auditIds)
+ {
+ return dataiSfLoginAuditMapper.deleteDataiSfLoginAuditByAuditIds(auditIds);
+ }
+
+ /**
+ * 删除登录审计日志信息
+ *
+ * @param auditId 登录审计日志主键
+ * @return 结果
+ */
+ @Override
+ public int deleteDataiSfLoginAuditByAuditId(Long auditId)
+ {
+ return dataiSfLoginAuditMapper.deleteDataiSfLoginAuditByAuditId(auditId);
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfLoginSessionServiceImpl.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfLoginSessionServiceImpl.java
new file mode 100644
index 00000000..1c0ff279
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfLoginSessionServiceImpl.java
@@ -0,0 +1,109 @@
+package com.datai.auth.service.impl;
+
+import java.util.List;
+
+import com.datai.common.core.domain.model.LoginUser;
+import com.datai.common.utils.DateUtils;
+ import com.datai.common.utils.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.datai.auth.mapper.DataiSfLoginSessionMapper;
+import com.datai.auth.domain.DataiSfLoginSession;
+import com.datai.auth.service.IDataiSfLoginSessionService;
+
+
+/**
+ * 登录会话Service业务层处理
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@Service
+public class DataiSfLoginSessionServiceImpl implements IDataiSfLoginSessionService {
+ @Autowired
+ private DataiSfLoginSessionMapper dataiSfLoginSessionMapper;
+
+ /**
+ * 查询登录会话
+ *
+ * @param sessionId 登录会话主键
+ * @return 登录会话
+ */
+ @Override
+ public DataiSfLoginSession selectDataiSfLoginSessionBySessionId(Long sessionId)
+ {
+ return dataiSfLoginSessionMapper.selectDataiSfLoginSessionBySessionId(sessionId);
+ }
+
+ /**
+ * 查询登录会话列表
+ *
+ * @param dataiSfLoginSession 登录会话
+ * @return 登录会话
+ */
+ @Override
+ public List selectDataiSfLoginSessionList(DataiSfLoginSession dataiSfLoginSession)
+ {
+ return dataiSfLoginSessionMapper.selectDataiSfLoginSessionList(dataiSfLoginSession);
+ }
+
+ /**
+ * 新增登录会话
+ *
+ * @param dataiSfLoginSession 登录会话
+ * @return 结果
+ */
+ @Override
+ public int insertDataiSfLoginSession(DataiSfLoginSession dataiSfLoginSession)
+ {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ String username = loginUser.getUsername();
+
+ dataiSfLoginSession.setCreateTime(DateUtils.getNowDate());
+ dataiSfLoginSession.setUpdateTime(DateUtils.getNowDate());
+ dataiSfLoginSession.setCreateBy(username);
+ dataiSfLoginSession.setUpdateBy(username);
+ return dataiSfLoginSessionMapper.insertDataiSfLoginSession(dataiSfLoginSession);
+ }
+
+ /**
+ * 修改登录会话
+ *
+ * @param dataiSfLoginSession 登录会话
+ * @return 结果
+ */
+ @Override
+ public int updateDataiSfLoginSession(DataiSfLoginSession dataiSfLoginSession)
+ {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ String username = loginUser.getUsername();
+
+ dataiSfLoginSession.setUpdateTime(DateUtils.getNowDate());
+ dataiSfLoginSession.setUpdateBy(username);
+ return dataiSfLoginSessionMapper.updateDataiSfLoginSession(dataiSfLoginSession);
+ }
+
+ /**
+ * 批量删除登录会话
+ *
+ * @param sessionIds 需要删除的登录会话主键
+ * @return 结果
+ */
+ @Override
+ public int deleteDataiSfLoginSessionBySessionIds(Long[] sessionIds)
+ {
+ return dataiSfLoginSessionMapper.deleteDataiSfLoginSessionBySessionIds(sessionIds);
+ }
+
+ /**
+ * 删除登录会话信息
+ *
+ * @param sessionId 登录会话主键
+ * @return 结果
+ */
+ @Override
+ public int deleteDataiSfLoginSessionBySessionId(Long sessionId)
+ {
+ return dataiSfLoginSessionMapper.deleteDataiSfLoginSessionBySessionId(sessionId);
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfLoginStatisticsServiceImpl.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfLoginStatisticsServiceImpl.java
new file mode 100644
index 00000000..7f251c01
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfLoginStatisticsServiceImpl.java
@@ -0,0 +1,109 @@
+package com.datai.auth.service.impl;
+
+import java.util.List;
+
+import com.datai.common.core.domain.model.LoginUser;
+import com.datai.common.utils.DateUtils;
+ import com.datai.common.utils.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.datai.auth.mapper.DataiSfLoginStatisticsMapper;
+import com.datai.auth.domain.DataiSfLoginStatistics;
+import com.datai.auth.service.IDataiSfLoginStatisticsService;
+
+
+/**
+ * 登录统计Service业务层处理
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@Service
+public class DataiSfLoginStatisticsServiceImpl implements IDataiSfLoginStatisticsService {
+ @Autowired
+ private DataiSfLoginStatisticsMapper dataiSfLoginStatisticsMapper;
+
+ /**
+ * 查询登录统计
+ *
+ * @param statId 登录统计主键
+ * @return 登录统计
+ */
+ @Override
+ public DataiSfLoginStatistics selectDataiSfLoginStatisticsByStatId(Long statId)
+ {
+ return dataiSfLoginStatisticsMapper.selectDataiSfLoginStatisticsByStatId(statId);
+ }
+
+ /**
+ * 查询登录统计列表
+ *
+ * @param dataiSfLoginStatistics 登录统计
+ * @return 登录统计
+ */
+ @Override
+ public List selectDataiSfLoginStatisticsList(DataiSfLoginStatistics dataiSfLoginStatistics)
+ {
+ return dataiSfLoginStatisticsMapper.selectDataiSfLoginStatisticsList(dataiSfLoginStatistics);
+ }
+
+ /**
+ * 新增登录统计
+ *
+ * @param dataiSfLoginStatistics 登录统计
+ * @return 结果
+ */
+ @Override
+ public int insertDataiSfLoginStatistics(DataiSfLoginStatistics dataiSfLoginStatistics)
+ {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ String username = loginUser.getUsername();
+
+ dataiSfLoginStatistics.setCreateTime(DateUtils.getNowDate());
+ dataiSfLoginStatistics.setUpdateTime(DateUtils.getNowDate());
+ dataiSfLoginStatistics.setCreateBy(username);
+ dataiSfLoginStatistics.setUpdateBy(username);
+ return dataiSfLoginStatisticsMapper.insertDataiSfLoginStatistics(dataiSfLoginStatistics);
+ }
+
+ /**
+ * 修改登录统计
+ *
+ * @param dataiSfLoginStatistics 登录统计
+ * @return 结果
+ */
+ @Override
+ public int updateDataiSfLoginStatistics(DataiSfLoginStatistics dataiSfLoginStatistics)
+ {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ String username = loginUser.getUsername();
+
+ dataiSfLoginStatistics.setUpdateTime(DateUtils.getNowDate());
+ dataiSfLoginStatistics.setUpdateBy(username);
+ return dataiSfLoginStatisticsMapper.updateDataiSfLoginStatistics(dataiSfLoginStatistics);
+ }
+
+ /**
+ * 批量删除登录统计
+ *
+ * @param statIds 需要删除的登录统计主键
+ * @return 结果
+ */
+ @Override
+ public int deleteDataiSfLoginStatisticsByStatIds(Long[] statIds)
+ {
+ return dataiSfLoginStatisticsMapper.deleteDataiSfLoginStatisticsByStatIds(statIds);
+ }
+
+ /**
+ * 删除登录统计信息
+ *
+ * @param statId 登录统计主键
+ * @return 结果
+ */
+ @Override
+ public int deleteDataiSfLoginStatisticsByStatId(Long statId)
+ {
+ return dataiSfLoginStatisticsMapper.deleteDataiSfLoginStatisticsByStatId(statId);
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfTokenBindingServiceImpl.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfTokenBindingServiceImpl.java
new file mode 100644
index 00000000..b9c2ecd8
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfTokenBindingServiceImpl.java
@@ -0,0 +1,109 @@
+package com.datai.auth.service.impl;
+
+import java.util.List;
+
+import com.datai.common.core.domain.model.LoginUser;
+import com.datai.common.utils.DateUtils;
+ import com.datai.common.utils.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.datai.auth.mapper.DataiSfTokenBindingMapper;
+import com.datai.auth.domain.DataiSfTokenBinding;
+import com.datai.auth.service.IDataiSfTokenBindingService;
+
+
+/**
+ * 令牌绑定Service业务层处理
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@Service
+public class DataiSfTokenBindingServiceImpl implements IDataiSfTokenBindingService {
+ @Autowired
+ private DataiSfTokenBindingMapper dataiSfTokenBindingMapper;
+
+ /**
+ * 查询令牌绑定
+ *
+ * @param bindingId 令牌绑定主键
+ * @return 令牌绑定
+ */
+ @Override
+ public DataiSfTokenBinding selectDataiSfTokenBindingByBindingId(Long bindingId)
+ {
+ return dataiSfTokenBindingMapper.selectDataiSfTokenBindingByBindingId(bindingId);
+ }
+
+ /**
+ * 查询令牌绑定列表
+ *
+ * @param dataiSfTokenBinding 令牌绑定
+ * @return 令牌绑定
+ */
+ @Override
+ public List selectDataiSfTokenBindingList(DataiSfTokenBinding dataiSfTokenBinding)
+ {
+ return dataiSfTokenBindingMapper.selectDataiSfTokenBindingList(dataiSfTokenBinding);
+ }
+
+ /**
+ * 新增令牌绑定
+ *
+ * @param dataiSfTokenBinding 令牌绑定
+ * @return 结果
+ */
+ @Override
+ public int insertDataiSfTokenBinding(DataiSfTokenBinding dataiSfTokenBinding)
+ {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ String username = loginUser.getUsername();
+
+ dataiSfTokenBinding.setCreateTime(DateUtils.getNowDate());
+ dataiSfTokenBinding.setUpdateTime(DateUtils.getNowDate());
+ dataiSfTokenBinding.setCreateBy(username);
+ dataiSfTokenBinding.setUpdateBy(username);
+ return dataiSfTokenBindingMapper.insertDataiSfTokenBinding(dataiSfTokenBinding);
+ }
+
+ /**
+ * 修改令牌绑定
+ *
+ * @param dataiSfTokenBinding 令牌绑定
+ * @return 结果
+ */
+ @Override
+ public int updateDataiSfTokenBinding(DataiSfTokenBinding dataiSfTokenBinding)
+ {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ String username = loginUser.getUsername();
+
+ dataiSfTokenBinding.setUpdateTime(DateUtils.getNowDate());
+ dataiSfTokenBinding.setUpdateBy(username);
+ return dataiSfTokenBindingMapper.updateDataiSfTokenBinding(dataiSfTokenBinding);
+ }
+
+ /**
+ * 批量删除令牌绑定
+ *
+ * @param bindingIds 需要删除的令牌绑定主键
+ * @return 结果
+ */
+ @Override
+ public int deleteDataiSfTokenBindingByBindingIds(Long[] bindingIds)
+ {
+ return dataiSfTokenBindingMapper.deleteDataiSfTokenBindingByBindingIds(bindingIds);
+ }
+
+ /**
+ * 删除令牌绑定信息
+ *
+ * @param bindingId 令牌绑定主键
+ * @return 结果
+ */
+ @Override
+ public int deleteDataiSfTokenBindingByBindingId(Long bindingId)
+ {
+ return dataiSfTokenBindingMapper.deleteDataiSfTokenBindingByBindingId(bindingId);
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfTokenServiceImpl.java b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfTokenServiceImpl.java
new file mode 100644
index 00000000..12e1320e
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/java/com/datai/auth/service/impl/DataiSfTokenServiceImpl.java
@@ -0,0 +1,109 @@
+package com.datai.auth.service.impl;
+
+import java.util.List;
+
+import com.datai.common.core.domain.model.LoginUser;
+import com.datai.common.utils.DateUtils;
+ import com.datai.common.utils.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.datai.auth.mapper.DataiSfTokenMapper;
+import com.datai.auth.domain.DataiSfToken;
+import com.datai.auth.service.IDataiSfTokenService;
+
+
+/**
+ * 令牌Service业务层处理
+ *
+ * @author datai
+ * @date 2025-12-14
+ */
+@Service
+public class DataiSfTokenServiceImpl implements IDataiSfTokenService {
+ @Autowired
+ private DataiSfTokenMapper dataiSfTokenMapper;
+
+ /**
+ * 查询令牌
+ *
+ * @param tokenId 令牌主键
+ * @return 令牌
+ */
+ @Override
+ public DataiSfToken selectDataiSfTokenByTokenId(Long tokenId)
+ {
+ return dataiSfTokenMapper.selectDataiSfTokenByTokenId(tokenId);
+ }
+
+ /**
+ * 查询令牌列表
+ *
+ * @param dataiSfToken 令牌
+ * @return 令牌
+ */
+ @Override
+ public List selectDataiSfTokenList(DataiSfToken dataiSfToken)
+ {
+ return dataiSfTokenMapper.selectDataiSfTokenList(dataiSfToken);
+ }
+
+ /**
+ * 新增令牌
+ *
+ * @param dataiSfToken 令牌
+ * @return 结果
+ */
+ @Override
+ public int insertDataiSfToken(DataiSfToken dataiSfToken)
+ {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ String username = loginUser.getUsername();
+
+ dataiSfToken.setCreateTime(DateUtils.getNowDate());
+ dataiSfToken.setUpdateTime(DateUtils.getNowDate());
+ dataiSfToken.setCreateBy(username);
+ dataiSfToken.setUpdateBy(username);
+ return dataiSfTokenMapper.insertDataiSfToken(dataiSfToken);
+ }
+
+ /**
+ * 修改令牌
+ *
+ * @param dataiSfToken 令牌
+ * @return 结果
+ */
+ @Override
+ public int updateDataiSfToken(DataiSfToken dataiSfToken)
+ {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ String username = loginUser.getUsername();
+
+ dataiSfToken.setUpdateTime(DateUtils.getNowDate());
+ dataiSfToken.setUpdateBy(username);
+ return dataiSfTokenMapper.updateDataiSfToken(dataiSfToken);
+ }
+
+ /**
+ * 批量删除令牌
+ *
+ * @param tokenIds 需要删除的令牌主键
+ * @return 结果
+ */
+ @Override
+ public int deleteDataiSfTokenByTokenIds(Long[] tokenIds)
+ {
+ return dataiSfTokenMapper.deleteDataiSfTokenByTokenIds(tokenIds);
+ }
+
+ /**
+ * 删除令牌信息
+ *
+ * @param tokenId 令牌主键
+ * @return 结果
+ */
+ @Override
+ public int deleteDataiSfTokenByTokenId(Long tokenId)
+ {
+ return dataiSfTokenMapper.deleteDataiSfTokenByTokenId(tokenId);
+ }
+}
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/doc/模块说明文档.md b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/doc/模块说明文档.md
new file mode 100644
index 00000000..5adeb4b4
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/doc/模块说明文档.md
@@ -0,0 +1,346 @@
+# datai-salesforce-auth - Salesforce登录认证模块
+
+## 1. 模块概述
+
+### 1.1 模块定位
+
+负责Salesforce登录认证和令牌管理,是所有需要访问Salesforce API的模块的基础。
+
+### 1.2 核心功能与职责
+
+- 支持多种Salesforce登录方式
+- 访问令牌和刷新令牌的管理
+- 登录状态的保存和获取
+- 登录审计日志记录
+- 令牌自动刷新机制
+- 登录失败锁定机制
+- 增强型令牌管理
+- 登录会话管理
+- 登录统计与报表
+
+### 1.3 设计思路
+
+采用策略模式设计,支持多种登录方式的扩展。使用Redis缓存存储登录状态,提高访问性能。实现令牌自动刷新机制,确保系统持续可用。引入分层架构,将控制器、服务层、策略层和数据访问层分离,便于维护和扩展。支持事件驱动设计,用于处理登录事件。
+
+## 2. 对外提供的接口/方法列表
+
+### 2.1 登录相关接口
+
+| 接口名称 | 方法签名 | 功能描述 | 参数说明 | 返回值 |
+|---------|---------|---------|---------|-------|
+| 登录接口 | `SalesforceLoginResult login(SalesforceLoginRequest request)` | 根据不同登录类型执行登录 | request:登录请求,包含登录类型、用户名、密码等信息 | 登录结果,包含访问令牌、实例URL等 |
+| 刷新令牌接口 | `SalesforceLoginResult refreshToken(String refreshToken, String loginType)` | 刷新访问令牌 | refreshToken:刷新令牌
loginType:登录类型 | 新的登录结果 |
+| 登出接口 | `boolean logout(String accessToken, String loginType)` | 执行登出操作 | accessToken:访问令牌
loginType:登录类型 | 登出是否成功 |
+| 获取当前登录状态 | `SalesforceLoginResult getCurrentLoginStatus()` | 获取当前登录状态 | 无 | 当前登录状态 |
+| 保存登录状态 | `void saveLoginStatus(SalesforceLoginResult result)` | 保存登录状态到缓存 | result:登录结果 | 无 |
+
+### 2.2 登录策略相关接口
+
+| 接口名称 | 方法签名 | 功能描述 | 参数说明 | 返回值 |
+|---------|---------|---------|---------|-------|
+| 获取登录策略 | `LoginStrategy getLoginStrategy(String loginType)` | 根据登录类型获取对应的登录策略 | loginType:登录类型 | 登录策略实现 |
+| 获取支持的登录类型 | `List getSupportedLoginTypes()` | 获取所有支持的登录类型 | 无 | 支持的登录类型列表 |
+
+
+
+### 2.6 令牌管理相关接口
+
+| 接口名称 | 方法签名 | 功能描述 | 参数说明 | 返回值 |
+|---------|---------|---------|---------|-------|
+| 验证令牌 | `boolean validateToken(String accessToken)` | 验证令牌有效性 | accessToken:访问令牌 | 是否有效 |
+| 吊销令牌 | `boolean revokeToken(String accessToken)` | 吊销令牌 | accessToken:访问令牌 | 是否吊销成功 |
+| 绑定令牌 | `void bindToken(String accessToken, String deviceId, String ip)` | 绑定令牌到设备/IP | accessToken:访问令牌
deviceId:设备ID
ip:IP地址 | 无 |
+| 检查令牌绑定 | `boolean checkTokenBinding(String accessToken, String deviceId, String ip)` | 检查令牌绑定 | accessToken:访问令牌
deviceId:设备ID
ip:IP地址 | 是否绑定匹配 |
+
+## 3. 内部实现的关键逻辑
+
+### 3.1 登录认证流程
+
+1. 客户端调用登录接口,传入登录请求
+2. 登录服务进行请求参数验证
+3. 登录服务根据登录类型获取对应的登录策略
+4. 执行具体的登录策略,调用Salesforce API获取令牌
+5. 保存登录会话到数据库和Redis缓存
+6. 记录登录审计日志
+7. 返回登录结果
+
+### 3.2 令牌刷新流程
+
+1. 系统定期检查登录会话的过期时间
+2. 当令牌即将过期时,自动调用刷新令牌接口
+3. 根据登录类型获取对应的登录策略
+4. 执行令牌刷新操作,获取新的访问令牌
+5. 更新登录会话的令牌信息
+6. 更新Redis缓存中的登录状态
+7. 记录令牌刷新日志
+
+### 3.6 关键类说明
+
+#### SalesforceLoginServiceImpl
+- 实现登录认证的核心逻辑
+- 管理登录策略的调用
+- 处理登录状态的保存与获取
+- 记录登录审计日志
+
+#### LoginStrategyFactory
+- 登录策略工厂,负责根据登录类型创建对应的登录策略
+- 支持策略的动态扩展
+
+#### OAuth2LoginStrategy
+- 实现OAuth 2.0登录策略
+- 支持OAuth 2.0授权码流程、密码流程和客户端凭证流程
+
+#### SalesforceCliLoginStrategy
+- 实现Salesforce CLI登录策略
+- 支持通过Salesforce CLI获取和使用访问令牌
+
+#### LegacyCredentialLoginStrategy
+- 实现传统账密凭证登录策略
+- 支持使用用户名、密码和安全令牌进行登录
+- 支持SOAP登录方式
+
+#### TokenManager
+- 令牌管理器,负责令牌的验证、吊销、绑定等操作
+- 支持令牌绑定设备/IP,提高安全性
+
+#### SalesforceConfigCacheManager
+- 配置缓存管理器,用于获取Salesforce API配置
+- 支持配置的动态更新
+
+## 4. 与其他模块的依赖关系
+
+### 4.1 依赖其他模块
+
+| 模块名称 | 依赖类型 | 用途 |
+|---------|---------|------|
+| datai-salesforce-common | 直接依赖 | 提供通用工具类和API客户端 |
+| datai-salesforce-config | 直接依赖 | 获取系统配置 |
+| datai-common | 直接依赖 | 提供基础框架支持和工具类 |
+| Redis缓存服务 | 外部依赖 | 存储登录状态、会话信息和临时数据 |
+| 数据库服务 | 外部依赖 | 存储登录审计日志、会话信息 |
+| Nimbus JOSE + JWT | 外部依赖 | JWT处理和验证 |
+| Spring Security OAuth2 | 外部依赖 | OAuth 2.0支持 |
+
+### 4.2 被其他模块依赖
+
+| 模块名称 | 依赖类型 | 用途 |
+|---------|---------|------|
+| datai-salesforce-meta | 直接依赖 | 获取Salesforce API访问权限 |
+| datai-salesforce-integration | 直接依赖 | 获取Salesforce API访问权限 |
+| datai-salesforce-dataloader | 直接依赖 | 获取Salesforce API访问权限 |
+| datai-salesforce-apex-lwc | 直接依赖 | 获取Salesforce API访问权限 |
+| datai-salesforce-report | 直接依赖 | 获取Salesforce API访问权限 |
+
+## 5. 数据流转路径说明
+
+### 5.1 登录认证数据流转
+
+```
+客户端 → 登录控制器 → 登录服务 → 登录策略 → Salesforce API → 登录结果 → 数据库存储 → Redis缓存 → 客户端
+```
+
+### 5.2 令牌刷新数据流转
+
+```
+系统定时检查 → 登录会话管理 → 刷新令牌服务 → 登录策略 → Salesforce API → 新令牌 → 数据库更新 → Redis缓存更新 → 登录状态更新
+```
+
+### 5.3 登出数据流转
+
+```
+客户端 → 登出控制器 → 登出服务 → 登录策略 → Salesforce API(可选) → Redis缓存清除 → 数据库更新 → 客户端
+```
+
+## 6. 性能与安全考量
+
+### 6.1 性能考量
+
+- 使用Redis缓存登录状态、会话信息和临时数据,减少数据库访问
+- 登录状态缓存支持可配置的过期时间
+- 令牌自动刷新机制,避免频繁手动刷新
+- 登录策略的懒加载,提高系统启动速度
+- 数据库查询优化,使用索引加速查询
+
+### 6.2 安全考量
+
+- 敏感信息在日志中掩码处理
+- 登录审计日志记录所有登录操作
+- 访问令牌定期刷新,支持令牌吊销
+- Redis缓存中的敏感信息加密存储
+- 支持多种认证方式,适应不同安全需求
+- 令牌绑定设备/IP,提高安全性
+- 安全的密码策略和密码存储
+- 支持强制密码更改和密码过期
+- 支持XSS和CSRF防护
+- 支持安全的CORS配置
+
+## 7. 典型使用场景
+
+### 7.1 OAuth 2.0登录场景
+
+```java
+// 创建登录请求
+SalesforceLoginRequest request = new SalesforceLoginRequest();
+request.setLoginType("oauth2");
+request.setUsername("user@example.com");
+request.setPassword("password123");
+request.setClientId("clientId");
+request.setClientSecret("clientSecret");
+request.setGrantType("password"); // 支持authorization_code, password, client_credentials
+
+// 执行登录
+SalesforceLoginResult result = salesforceLoginService.login(request);
+
+// 处理登录结果
+if (result.isSuccess()) {
+ // 登录成功,获取访问令牌
+ String accessToken = result.getAccessToken();
+ String instanceUrl = result.getInstanceUrl();
+ // 使用访问令牌调用Salesforce API
+} else {
+ // 登录失败,处理错误信息
+ String errorMessage = result.getErrorMessage();
+}
+```
+
+### 7.2 Salesforce CLI登录场景
+
+```java
+// 创建登录请求
+SalesforceLoginRequest request = new SalesforceLoginRequest();
+request.setLoginType("salesforce_cli");
+request.setUsername("user@example.com");
+request.setOrgAlias("my-sandbox"); // 可选,使用已登录的CLI组织别名
+
+// 执行登录
+SalesforceLoginResult result = salesforceLoginService.login(request);
+
+// 处理登录结果
+if (result.isSuccess()) {
+ // 登录成功,获取访问令牌
+ String accessToken = result.getAccessToken();
+ String instanceUrl = result.getInstanceUrl();
+ // 使用访问令牌调用Salesforce API
+} else {
+ // 登录失败,处理错误信息
+ String errorMessage = result.getErrorMessage();
+}
+```
+
+### 7.3 传统账密凭证登录场景
+
+```java
+// 创建登录请求
+SalesforceLoginRequest request = new SalesforceLoginRequest();
+request.setLoginType("legacy_credential");
+request.setUsername("user@example.com");
+request.setPassword("password123");
+request.setSecurityToken("securityToken123");
+
+// 执行登录
+SalesforceLoginResult result = salesforceLoginService.login(request);
+
+// 处理登录结果
+if (result.isSuccess()) {
+ // 登录成功,获取访问令牌
+ String accessToken = result.getAccessToken();
+ String instanceUrl = result.getInstanceUrl();
+ // 使用访问令牌调用Salesforce API
+} else {
+ // 登录失败,处理错误信息
+ String errorMessage = result.getErrorMessage();
+}
+```
+
+### 7.4 令牌管理场景
+
+```java
+// 验证令牌
+boolean isValid = tokenManager.validateToken(accessToken);
+if (isValid) {
+ // 令牌有效,继续处理
+}
+
+// 吊销令牌
+boolean revoked = tokenManager.revokeToken(accessToken);
+if (revoked) {
+ // 令牌已吊销
+}
+
+// 绑定令牌
+String deviceId = "device-123";
+String ip = "192.168.1.1";
+tokenManager.bindToken(accessToken, deviceId, ip);
+
+// 检查令牌绑定
+boolean bound = tokenManager.checkTokenBinding(accessToken, deviceId, ip);
+if (bound) {
+ // 令牌绑定匹配
+}
+```
+
+## 8. 维护指南
+
+### 8.1 常见问题排查
+
+| 问题 | 可能原因 | 解决方案 |
+|------|----------|----------|
+| 登录失败 | 登录类型不正确 | 检查登录类型是否在支持列表中 |
+| 登录失败 | 用户名密码错误 | 检查用户名密码和安全令牌是否正确 |
+| 登录失败 | 客户端ID/Secret错误 | 检查OAuth应用配置是否正确 |
+| 令牌刷新失败 | 刷新令牌无效 | 重新登录获取新的刷新令牌 |
+| 令牌刷新失败 | Salesforce API连接异常 | 检查网络连接和API配置 |
+| 登录状态获取失败 | Redis缓存异常 | 检查Redis服务是否正常运行 |
+| 登录状态获取失败 | 登录会话已过期 | 重新登录获取新的会话 |
+| 登录被锁定 | 登录失败次数过多 | 等待锁定时间过期或手动解锁 |
+
+### 8.2 日志查看
+
+- 登录相关日志:搜索"SalesforceLoginServiceImpl"关键字
+- 登录策略相关日志:搜索"LoginStrategy"关键字
+- 令牌管理相关日志:搜索"TokenManager"关键字
+- 配置相关日志:搜索"SalesforceConfigCacheManager"关键字
+- 登录审计日志:搜索"SalesforceLoginAudit"关键字
+
+### 8.3 监控指标
+
+- 登录成功率:监控登录成功与失败的比例
+- 令牌刷新成功率:监控令牌刷新成功与失败的比例
+- 登录请求频率:监控单位时间内的登录请求次数
+- 缓存命中率:监控登录状态和会话缓存的命中率
+- 会话平均时长:监控登录会话的平均持续时间
+- 登录失败次数:监控登录失败的次数和趋势
+- 令牌吊销数量:监控令牌吊销的数量
+- API调用成功率:监控与Salesforce API的调用成功率
+
+## 9. 扩展点与自定义
+
+### 9.1 添加新的登录方式
+
+1. 创建新的登录策略类,实现LoginStrategy接口
+2. 在策略类上添加@Component注解
+3. 实现login、refreshToken和logout方法
+4. 系统自动识别并加载新的登录策略
+
+### 9.5 自定义配置
+
+可以通过配置文件或数据库配置以下参数:
+- Salesforce API版本
+- 登录超时时间
+- 令牌过期时间
+- Redis缓存过期时间
+- 登录失败锁定配置(锁定时长、解锁方式等)
+- 审计日志保留配置
+
+## 10. 版本历史
+
+| 版本 | 发布日期 | 主要变更 |
+|------|---------|---------|
+| 1.0.0 | 2025-12-11 | 初始版本,支持密码登录、JWT登录、客户端凭证登录 |
+| 1.1.0 | 2025-12-11 | 增强版本,添加登录失败锁定、增强型令牌管理、登录会话管理、登录统计与报表功能 |
+
+## 11. 联系方式
+
+- 模块负责人:系统重构小组
+- 联系邮箱:team@example.com
+- 文档更新日期:2025-12-11
\ No newline at end of file
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfFailedLoginMapper.xml b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfFailedLoginMapper.xml
new file mode 100644
index 00000000..15c5babb
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfFailedLoginMapper.xml
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select
+ dsfl.failed_id,
+ dsfl.tenant_id,
+ dsfl.username,
+ dsfl.login_type,
+ dsfl.failed_time,
+ dsfl.failed_reason,
+ dsfl.ip_address,
+ dsfl.device_info,
+ dsfl.lock_status,
+ dsfl.lock_time,
+ dsfl.unlock_time,
+ dsfl.lock_reason,
+ dsfl.create_by,
+ dsfl.create_time
+ from datai_sf_failed_login dsfl
+
+
+
+
+
+
+
+ insert into datai_sf_failed_login
+
+ tenant_id,
+ username,
+ login_type,
+ failed_time,
+ failed_reason,
+ ip_address,
+ device_info,
+ lock_status,
+ lock_time,
+ unlock_time,
+ lock_reason,
+ create_by,
+ create_time,
+
+
+ #{tenantId},
+ #{username},
+ #{loginType},
+ #{failedTime},
+ #{failedReason},
+ #{ipAddress},
+ #{deviceInfo},
+ #{lockStatus},
+ #{lockTime},
+ #{unlockTime},
+ #{lockReason},
+ #{createBy},
+ #{createTime},
+
+
+
+
+ update datai_sf_failed_login
+
+ tenant_id = #{tenantId},
+ username = #{username},
+ login_type = #{loginType},
+ failed_time = #{failedTime},
+ failed_reason = #{failedReason},
+ ip_address = #{ipAddress},
+ device_info = #{deviceInfo},
+ lock_status = #{lockStatus},
+ lock_time = #{lockTime},
+ unlock_time = #{unlockTime},
+ lock_reason = #{lockReason},
+ create_by = #{createBy},
+ create_time = #{createTime},
+
+ where datai_sf_failed_login.failed_id = #{failedId}
+
+
+
+ delete from datai_sf_failed_login where failed_id = #{failedId}
+
+
+
+ delete from datai_sf_failed_login where failed_id in
+
+ #{failedId}
+
+
+
\ No newline at end of file
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfLoginAuditMapper.xml b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfLoginAuditMapper.xml
new file mode 100644
index 00000000..6b0577e9
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfLoginAuditMapper.xml
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select
+ dsla.audit_id,
+ dsla.tenant_id,
+ dsla.username,
+ dsla.operation_type,
+ dsla.result,
+ dsla.operation_time,
+ dsla.ip_address,
+ dsla.device_info,
+ dsla.browser_info,
+ dsla.login_type,
+ dsla.error_message,
+ dsla.session_id,
+ dsla.token_id,
+ dsla.request_id,
+ dsla.create_by,
+ dsla.create_time
+ from datai_sf_login_audit dsla
+
+
+
+
+
+
+
+ insert into datai_sf_login_audit
+
+ tenant_id,
+ username,
+ operation_type,
+ result,
+ operation_time,
+ ip_address,
+ device_info,
+ browser_info,
+ login_type,
+ error_message,
+ session_id,
+ token_id,
+ request_id,
+ create_by,
+ create_time,
+
+
+ #{tenantId},
+ #{username},
+ #{operationType},
+ #{result},
+ #{operationTime},
+ #{ipAddress},
+ #{deviceInfo},
+ #{browserInfo},
+ #{loginType},
+ #{errorMessage},
+ #{sessionId},
+ #{tokenId},
+ #{requestId},
+ #{createBy},
+ #{createTime},
+
+
+
+
+ update datai_sf_login_audit
+
+ tenant_id = #{tenantId},
+ username = #{username},
+ operation_type = #{operationType},
+ result = #{result},
+ operation_time = #{operationTime},
+ ip_address = #{ipAddress},
+ device_info = #{deviceInfo},
+ browser_info = #{browserInfo},
+ login_type = #{loginType},
+ error_message = #{errorMessage},
+ session_id = #{sessionId},
+ token_id = #{tokenId},
+ request_id = #{requestId},
+ create_by = #{createBy},
+ create_time = #{createTime},
+
+ where datai_sf_login_audit.audit_id = #{auditId}
+
+
+
+ delete from datai_sf_login_audit where audit_id = #{auditId}
+
+
+
+ delete from datai_sf_login_audit where audit_id in
+
+ #{auditId}
+
+
+
\ No newline at end of file
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfLoginSessionMapper.xml b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfLoginSessionMapper.xml
new file mode 100644
index 00000000..8c3f615f
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfLoginSessionMapper.xml
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select
+ dsls.session_id,
+ dsls.tenant_id,
+ dsls.username,
+ dsls.login_type,
+ dsls.status,
+ dsls.login_time,
+ dsls.expire_time,
+ dsls.last_activity_time,
+ dsls.login_ip,
+ dsls.device_info,
+ dsls.browser_info,
+ dsls.session_token,
+ dsls.token_id,
+ dsls.create_by,
+ dsls.create_time,
+ dsls.update_by,
+ dsls.update_time
+ from datai_sf_login_session dsls
+
+
+
+
+
+
+
+ insert into datai_sf_login_session
+
+ tenant_id,
+ username,
+ login_type,
+ status,
+ login_time,
+ expire_time,
+ last_activity_time,
+ login_ip,
+ device_info,
+ browser_info,
+ session_token,
+ token_id,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+
+
+ #{tenantId},
+ #{username},
+ #{loginType},
+ #{status},
+ #{loginTime},
+ #{expireTime},
+ #{lastActivityTime},
+ #{loginIp},
+ #{deviceInfo},
+ #{browserInfo},
+ #{sessionToken},
+ #{tokenId},
+ #{createBy},
+ #{createTime},
+ #{updateBy},
+ #{updateTime},
+
+
+
+
+ update datai_sf_login_session
+
+ tenant_id = #{tenantId},
+ username = #{username},
+ login_type = #{loginType},
+ status = #{status},
+ login_time = #{loginTime},
+ expire_time = #{expireTime},
+ last_activity_time = #{lastActivityTime},
+ login_ip = #{loginIp},
+ device_info = #{deviceInfo},
+ browser_info = #{browserInfo},
+ session_token = #{sessionToken},
+ token_id = #{tokenId},
+ create_by = #{createBy},
+ create_time = #{createTime},
+ update_by = #{updateBy},
+ update_time = #{updateTime},
+
+ where datai_sf_login_session.session_id = #{sessionId}
+
+
+
+ delete from datai_sf_login_session where session_id = #{sessionId}
+
+
+
+ delete from datai_sf_login_session where session_id in
+
+ #{sessionId}
+
+
+
\ No newline at end of file
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfLoginStatisticsMapper.xml b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfLoginStatisticsMapper.xml
new file mode 100644
index 00000000..712c6c1c
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfLoginStatisticsMapper.xml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select
+ dsls.stat_id,
+ dsls.tenant_id,
+ dsls.stat_date,
+ dsls.stat_hour,
+ dsls.login_type,
+ dsls.success_count,
+ dsls.failed_count,
+ dsls.refresh_count,
+ dsls.revoke_count,
+ dsls.create_by,
+ dsls.create_time,
+ dsls.update_by,
+ dsls.update_time
+ from datai_sf_login_statistics dsls
+
+
+
+
+
+
+
+ insert into datai_sf_login_statistics
+
+ tenant_id,
+ stat_date,
+ stat_hour,
+ login_type,
+ success_count,
+ failed_count,
+ refresh_count,
+ revoke_count,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+
+
+ #{tenantId},
+ #{statDate},
+ #{statHour},
+ #{loginType},
+ #{successCount},
+ #{failedCount},
+ #{refreshCount},
+ #{revokeCount},
+ #{createBy},
+ #{createTime},
+ #{updateBy},
+ #{updateTime},
+
+
+
+
+ update datai_sf_login_statistics
+
+ tenant_id = #{tenantId},
+ stat_date = #{statDate},
+ stat_hour = #{statHour},
+ login_type = #{loginType},
+ success_count = #{successCount},
+ failed_count = #{failedCount},
+ refresh_count = #{refreshCount},
+ revoke_count = #{revokeCount},
+ create_by = #{createBy},
+ create_time = #{createTime},
+ update_by = #{updateBy},
+ update_time = #{updateTime},
+
+ where datai_sf_login_statistics.stat_id = #{statId}
+
+
+
+ delete from datai_sf_login_statistics where stat_id = #{statId}
+
+
+
+ delete from datai_sf_login_statistics where stat_id in
+
+ #{statId}
+
+
+
\ No newline at end of file
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfTokenBindingMapper.xml b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfTokenBindingMapper.xml
new file mode 100644
index 00000000..afbfefda
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfTokenBindingMapper.xml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select
+ dstb.binding_id,
+ dstb.tenant_id,
+ dstb.token_id,
+ dstb.binding_type,
+ dstb.device_id,
+ dstb.binding_ip,
+ dstb.status,
+ dstb.binding_time,
+ dstb.expire_time,
+ dstb.create_by,
+ dstb.create_time,
+ dstb.update_by,
+ dstb.update_time
+ from datai_sf_token_binding dstb
+
+
+
+
+
+
+
+ insert into datai_sf_token_binding
+
+ tenant_id,
+ token_id,
+ binding_type,
+ device_id,
+ binding_ip,
+ status,
+ binding_time,
+ expire_time,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+
+
+ #{tenantId},
+ #{tokenId},
+ #{bindingType},
+ #{deviceId},
+ #{bindingIp},
+ #{status},
+ #{bindingTime},
+ #{expireTime},
+ #{createBy},
+ #{createTime},
+ #{updateBy},
+ #{updateTime},
+
+
+
+
+ update datai_sf_token_binding
+
+ tenant_id = #{tenantId},
+ token_id = #{tokenId},
+ binding_type = #{bindingType},
+ device_id = #{deviceId},
+ binding_ip = #{bindingIp},
+ status = #{status},
+ binding_time = #{bindingTime},
+ expire_time = #{expireTime},
+ create_by = #{createBy},
+ create_time = #{createTime},
+ update_by = #{updateBy},
+ update_time = #{updateTime},
+
+ where datai_sf_token_binding.binding_id = #{bindingId}
+
+
+
+ delete from datai_sf_token_binding where binding_id = #{bindingId}
+
+
+
+ delete from datai_sf_token_binding where binding_id in
+
+ #{bindingId}
+
+
+
\ No newline at end of file
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfTokenMapper.xml b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfTokenMapper.xml
new file mode 100644
index 00000000..d18b1efc
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/mapper/auth/DataiSfTokenMapper.xml
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select
+ dst.token_id,
+ dst.tenant_id,
+ dst.username,
+ dst.access_token,
+ dst.refresh_token,
+ dst.access_token_expire,
+ dst.refresh_token_expire,
+ dst.status,
+ dst.instance_url,
+ dst.login_type,
+ dst.client_id,
+ dst.scope,
+ dst.token_type,
+ dst.organization_id,
+ dst.user_id,
+ dst.create_by,
+ dst.create_time,
+ dst.update_by,
+ dst.update_time
+ from datai_sf_token dst
+
+
+
+
+
+
+
+ insert into datai_sf_token
+
+ tenant_id,
+ username,
+ access_token,
+ refresh_token,
+ access_token_expire,
+ refresh_token_expire,
+ status,
+ instance_url,
+ login_type,
+ client_id,
+ scope,
+ token_type,
+ organization_id,
+ user_id,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+
+
+ #{tenantId},
+ #{username},
+ #{accessToken},
+ #{refreshToken},
+ #{accessTokenExpire},
+ #{refreshTokenExpire},
+ #{status},
+ #{instanceUrl},
+ #{loginType},
+ #{clientId},
+ #{scope},
+ #{tokenType},
+ #{organizationId},
+ #{userId},
+ #{createBy},
+ #{createTime},
+ #{updateBy},
+ #{updateTime},
+
+
+
+
+ update datai_sf_token
+
+ tenant_id = #{tenantId},
+ username = #{username},
+ access_token = #{accessToken},
+ refresh_token = #{refreshToken},
+ access_token_expire = #{accessTokenExpire},
+ refresh_token_expire = #{refreshTokenExpire},
+ status = #{status},
+ instance_url = #{instanceUrl},
+ login_type = #{loginType},
+ client_id = #{clientId},
+ scope = #{scope},
+ token_type = #{tokenType},
+ organization_id = #{organizationId},
+ user_id = #{userId},
+ create_by = #{createBy},
+ create_time = #{createTime},
+ update_by = #{updateBy},
+ update_time = #{updateTime},
+
+ where datai_sf_token.token_id = #{tokenId}
+
+
+
+ delete from datai_sf_token where token_id = #{tokenId}
+
+
+
+ delete from datai_sf_token where token_id in
+
+ #{tokenId}
+
+
+
\ No newline at end of file
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/sql/salesforce-auth-tables.sql b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/sql/salesforce-auth-tables.sql
new file mode 100644
index 00000000..864a8fba
--- /dev/null
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-auth/src/main/resources/sql/salesforce-auth-tables.sql
@@ -0,0 +1,346 @@
+-- datai-salesforce-auth 模块数据库表结构
+-- 该模块负责Salesforce登录认证和令牌管理,是所有需要访问Salesforce API的模块的基础
+
+-- -----------------------------
+-- 登录会话表 (datai_sf_login_session)
+-- -----------------------------
+-- 用途:存储登录会话信息,用于会话管理和令牌刷新
+-- 设计考虑:
+-- 1. 支持多种登录方式
+-- 2. 支持会话状态管理
+-- 3. 支持令牌自动刷新
+-- 4. 支持多租户隔离
+CREATE TABLE `datai_sf_login_session` (
+ -- 会话ID,自增主键,唯一标识一个登录会话
+ `session_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '会话ID',
+ -- 租户编号,支持多租户隔离
+ `tenant_id` VARCHAR(32) DEFAULT NULL COMMENT '租户编号',
+ -- 用户名,登录用户的Salesforce用户名
+ `username` VARCHAR(255) NOT NULL COMMENT '用户名',
+ -- 登录类型,如oauth2、salesforce_cli、legacy_credential等
+ `login_type` VARCHAR(50) NOT NULL COMMENT '登录类型',
+ -- 会话状态,如ACTIVE、EXPIRED、REVOKED、INVALID
+ `status` VARCHAR(20) NOT NULL COMMENT '会话状态',
+ -- 登录时间,会话创建时间
+ `login_time` DATETIME NOT NULL COMMENT '登录时间',
+ -- 过期时间,会话过期时间
+ `expire_time` DATETIME NOT NULL COMMENT '过期时间',
+ -- 最后活动时间,会话最后活跃时间
+ `last_activity_time` DATETIME NOT NULL COMMENT '最后活动时间',
+ -- 登录IP地址,用户登录时的IP地址
+ `login_ip` VARCHAR(50) DEFAULT NULL COMMENT '登录IP',
+ -- 登录设备信息,用户登录时的设备信息
+ `device_info` VARCHAR(500) DEFAULT NULL COMMENT '设备信息',
+ -- 浏览器信息,用户登录时的浏览器信息
+ `browser_info` VARCHAR(500) DEFAULT NULL COMMENT '浏览器信息',
+ -- 会话标识,用于标识会话的唯一字符串
+ `session_token` VARCHAR(255) DEFAULT NULL COMMENT '会话标识',
+ -- 关联的令牌ID,关联到令牌表
+ `token_id` BIGINT(20) DEFAULT NULL COMMENT '令牌ID',
+ -- 创建人,记录创建会话的用户
+ `create_by` VARCHAR(64) DEFAULT NULL COMMENT '创建人',
+ -- 创建时间,记录会话创建的时间
+ `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
+ -- 更新人,记录最后更新会话的用户
+ `update_by` VARCHAR(64) DEFAULT NULL COMMENT '更新人',
+ -- 更新时间,记录会话最后更新的时间
+ `update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
+ -- 主键索引,唯一标识会话记录
+ PRIMARY KEY (`session_id`),
+ -- 普通索引,加速按用户名查询会话
+ KEY `idx_username` (`username`),
+ -- 普通索引,加速按登录类型查询会话
+ KEY `idx_login_type` (`login_type`),
+ -- 普通索引,加速按会话状态查询会话
+ KEY `idx_status` (`status`),
+ -- 普通索引,加速按过期时间查询会话
+ KEY `idx_expire_time` (`expire_time`),
+ -- 普通索引,加速按租户编号查询会话
+ KEY `idx_tenant_id` (`tenant_id`),
+ -- 普通索引,加速按令牌ID查询会话
+ KEY `idx_token_id` (`token_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='登录会话表,存储登录会话信息,用于会话管理和令牌刷新';
+
+-- -----------------------------
+-- 令牌表 (datai_sf_token)
+-- -----------------------------
+-- 用途:存储访问令牌和刷新令牌信息,用于令牌管理和验证
+-- 设计考虑:
+-- 1. 支持访问令牌和刷新令牌的存储
+-- 2. 支持令牌状态管理
+-- 3. 支持令牌过期时间管理
+-- 4. 支持多租户隔离
+CREATE TABLE `datai_sf_token` (
+ -- 令牌ID,自增主键,唯一标识一个令牌记录
+ `token_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '令牌ID',
+ -- 租户编号,支持多租户隔离
+ `tenant_id` VARCHAR(32) DEFAULT NULL COMMENT '租户编号',
+ -- 用户名,令牌所属用户的Salesforce用户名
+ `username` VARCHAR(255) NOT NULL COMMENT '用户名',
+ -- 访问令牌,用于访问Salesforce API
+ `access_token` VARCHAR(1024) NOT NULL COMMENT '访问令牌',
+ -- 刷新令牌,用于刷新访问令牌
+ `refresh_token` VARCHAR(1024) DEFAULT NULL COMMENT '刷新令牌',
+ -- 访问令牌过期时间
+ `access_token_expire` DATETIME NOT NULL COMMENT '访问令牌过期时间',
+ -- 刷新令牌过期时间
+ `refresh_token_expire` DATETIME DEFAULT NULL COMMENT '刷新令牌过期时间',
+ -- 令牌状态,如ACTIVE、EXPIRED、REVOKED、INVALID
+ `status` VARCHAR(20) NOT NULL COMMENT '令牌状态',
+ -- 实例URL,Salesforce实例URL
+ `instance_url` VARCHAR(255) NOT NULL COMMENT '实例URL',
+ -- 登录类型,如oauth2、salesforce_cli、legacy_credential等
+ `login_type` VARCHAR(50) NOT NULL COMMENT '登录类型',
+ -- 客户端ID,OAuth应用的客户端ID
+ `client_id` VARCHAR(255) DEFAULT NULL COMMENT '客户端ID',
+ -- 作用域,令牌的作用域
+ `scope` VARCHAR(255) DEFAULT NULL COMMENT '作用域',
+ -- 令牌类型,如Bearer
+ `token_type` VARCHAR(50) DEFAULT NULL COMMENT '令牌类型',
+ -- 组织ID,Salesforce组织ID
+ `organization_id` VARCHAR(50) DEFAULT NULL COMMENT '组织ID',
+ -- 用户ID,Salesforce用户ID
+ `user_id` VARCHAR(50) DEFAULT NULL COMMENT '用户ID',
+ -- 创建人,记录创建令牌的用户
+ `create_by` VARCHAR(64) DEFAULT NULL COMMENT '创建人',
+ -- 创建时间,记录令牌创建的时间
+ `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
+ -- 更新人,记录最后更新令牌的用户
+ `update_by` VARCHAR(64) DEFAULT NULL COMMENT '更新人',
+ -- 更新时间,记录令牌最后更新的时间
+ `update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
+ -- 主键索引,唯一标识令牌记录
+ PRIMARY KEY (`token_id`),
+ -- 普通索引,加速按用户名查询令牌
+ KEY `idx_username` (`username`),
+ -- 普通索引,加速按访问令牌查询令牌
+ KEY `idx_access_token` (`access_token`(255)),
+ -- 普通索引,加速按刷新令牌查询令牌
+ KEY `idx_refresh_token` (`refresh_token`(255)),
+ -- 普通索引,加速按令牌状态查询令牌
+ KEY `idx_status` (`status`),
+ -- 普通索引,加速按访问令牌过期时间查询令牌
+ KEY `idx_access_expire` (`access_token_expire`),
+ -- 普通索引,加速按刷新令牌过期时间查询令牌
+ KEY `idx_refresh_expire` (`refresh_token_expire`),
+ -- 普通索引,加速按租户编号查询令牌
+ KEY `idx_tenant_id` (`tenant_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='令牌表,存储访问令牌和刷新令牌信息,用于令牌管理和验证';
+
+-- -----------------------------
+-- 登录审计日志表 (datai_sf_login_audit)
+-- -----------------------------
+-- 用途:记录登录相关操作,用于审计和安全分析
+-- 设计考虑:
+-- 1. 支持多种操作类型的记录
+-- 2. 支持登录结果的记录
+-- 3. 支持详细的操作上下文信息
+-- 4. 支持多租户隔离
+CREATE TABLE `datai_sf_login_audit` (
+ -- 日志ID,自增主键,唯一标识一条审计日志
+ `audit_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '日志ID',
+ -- 租户编号,支持多租户隔离
+ `tenant_id` VARCHAR(32) DEFAULT NULL COMMENT '租户编号',
+ -- 用户名,操作相关的用户名
+ `username` VARCHAR(255) DEFAULT NULL COMMENT '用户名',
+ -- 操作类型,如LOGIN、LOGOUT、REFRESH_TOKEN、VALIDATE_TOKEN、REVOKE_TOKEN等
+ `operation_type` VARCHAR(50) NOT NULL COMMENT '操作类型',
+ -- 操作结果,如SUCCESS、FAILED、REJECTED
+ `result` VARCHAR(20) NOT NULL COMMENT '操作结果',
+ -- 操作时间,记录操作执行的时间
+ `operation_time` DATETIME NOT NULL COMMENT '操作时间',
+ -- 操作IP地址,记录执行操作的客户端IP
+ `ip_address` VARCHAR(50) DEFAULT NULL COMMENT 'IP地址',
+ -- 设备信息,记录执行操作的设备信息
+ `device_info` VARCHAR(500) DEFAULT NULL COMMENT '设备信息',
+ -- 浏览器信息,记录执行操作的浏览器信息
+ `browser_info` VARCHAR(500) DEFAULT NULL COMMENT '浏览器信息',
+ -- 登录类型,如oauth2、salesforce_cli、legacy_credential等
+ `login_type` VARCHAR(50) DEFAULT NULL COMMENT '登录类型',
+ -- 错误信息,记录操作失败时的错误详情
+ `error_message` TEXT DEFAULT NULL COMMENT '错误信息',
+ -- 会话ID,关联到登录会话表
+ `session_id` BIGINT(20) DEFAULT NULL COMMENT '会话ID',
+ -- 令牌ID,关联到令牌表
+ `token_id` BIGINT(20) DEFAULT NULL COMMENT '令牌ID',
+ -- 请求ID,用于关联同一请求的多个操作日志
+ `request_id` VARCHAR(36) DEFAULT NULL COMMENT '请求ID',
+ -- 创建人,记录创建日志的用户
+ `create_by` VARCHAR(64) DEFAULT NULL COMMENT '创建人',
+ -- 创建时间,记录日志创建的时间
+ `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
+ -- 主键索引,唯一标识审计日志记录
+ PRIMARY KEY (`audit_id`),
+ -- 普通索引,加速按用户名查询审计日志
+ KEY `idx_username` (`username`),
+ -- 普通索引,加速按操作类型查询审计日志
+ KEY `idx_operation_type` (`operation_type`),
+ -- 普通索引,加速按操作结果查询审计日志
+ KEY `idx_result` (`result`),
+ -- 普通索引,加速按操作时间查询审计日志
+ KEY `idx_operation_time` (`operation_time`),
+ -- 普通索引,加速按登录类型查询审计日志
+ KEY `idx_login_type` (`login_type`),
+ -- 普通索引,加速按租户编号查询审计日志
+ KEY `idx_tenant_id` (`tenant_id`),
+ -- 普通索引,加速按会话ID查询审计日志
+ KEY `idx_session_id` (`session_id`),
+ -- 普通索引,加速按令牌ID查询审计日志
+ KEY `idx_token_id` (`token_id`),
+ -- 普通索引,加速按请求ID查询审计日志
+ KEY `idx_request_id` (`request_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='登录审计日志表,记录登录相关操作,用于审计和安全分析';
+
+-- -----------------------------
+-- 令牌绑定表 (datai_sf_token_binding)
+-- -----------------------------
+-- 用途:记录令牌与设备/IP的绑定关系,用于提高安全性
+-- 设计考虑:
+-- 1. 支持令牌与设备的绑定
+-- 2. 支持令牌与IP的绑定
+-- 3. 支持绑定状态管理
+-- 4. 支持多租户隔离
+CREATE TABLE `datai_sf_token_binding` (
+ -- 绑定ID,自增主键,唯一标识一个令牌绑定
+ `binding_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '绑定ID',
+ -- 租户编号,支持多租户隔离
+ `tenant_id` VARCHAR(32) DEFAULT NULL COMMENT '租户编号',
+ -- 令牌ID,关联到令牌表
+ `token_id` BIGINT(20) NOT NULL COMMENT '令牌ID',
+ -- 绑定类型,如DEVICE、IP、DEVICE_IP
+ `binding_type` VARCHAR(20) NOT NULL COMMENT '绑定类型',
+ -- 设备ID,令牌绑定的设备标识
+ `device_id` VARCHAR(255) DEFAULT NULL COMMENT '设备ID',
+ -- 绑定IP地址,令牌绑定的IP地址
+ `binding_ip` VARCHAR(50) DEFAULT NULL COMMENT '绑定IP',
+ -- 绑定状态,如ACTIVE、EXPIRED、REVOKED
+ `status` VARCHAR(20) NOT NULL COMMENT '绑定状态',
+ -- 绑定时间,记录令牌绑定的时间
+ `binding_time` DATETIME NOT NULL COMMENT '绑定时间',
+ -- 过期时间,记录令牌绑定的过期时间
+ `expire_time` DATETIME DEFAULT NULL COMMENT '过期时间',
+ -- 创建人,记录创建令牌绑定的用户
+ `create_by` VARCHAR(64) DEFAULT NULL COMMENT '创建人',
+ -- 创建时间,记录令牌绑定创建的时间
+ `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
+ -- 更新人,记录最后更新令牌绑定的用户
+ `update_by` VARCHAR(64) DEFAULT NULL COMMENT '更新人',
+ -- 更新时间,记录令牌绑定最后更新的时间
+ `update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
+ -- 主键索引,唯一标识令牌绑定记录
+ PRIMARY KEY (`binding_id`),
+ -- 普通索引,加速按令牌ID查询令牌绑定
+ KEY `idx_token_id` (`token_id`),
+ -- 普通索引,加速按绑定类型查询令牌绑定
+ KEY `idx_binding_type` (`binding_type`),
+ -- 普通索引,加速按设备ID查询令牌绑定
+ KEY `idx_device_id` (`device_id`),
+ -- 普通索引,加速按绑定IP查询令牌绑定
+ KEY `idx_binding_ip` (`binding_ip`),
+ -- 普通索引,加速按绑定状态查询令牌绑定
+ KEY `idx_status` (`status`),
+ -- 普通索引,加速按租户编号查询令牌绑定
+ KEY `idx_tenant_id` (`tenant_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='令牌绑定表,记录令牌与设备/IP的绑定关系,用于提高安全性';
+
+-- -----------------------------
+-- 失败登录表 (datai_sf_failed_login)
+-- -----------------------------
+-- 用途:记录登录失败尝试,用于登录锁定和风险检测
+-- 设计考虑:
+-- 1. 支持记录登录失败原因
+-- 2. 支持按用户名和IP统计失败次数
+-- 3. 支持登录锁定机制
+-- 4. 支持多租户隔离
+CREATE TABLE `datai_sf_failed_login` (
+ -- 记录ID,自增主键,唯一标识一条失败登录记录
+ `failed_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '记录ID',
+ -- 租户编号,支持多租户隔离
+ `tenant_id` VARCHAR(32) DEFAULT NULL COMMENT '租户编号',
+ -- 用户名,登录失败的用户名
+ `username` VARCHAR(255) DEFAULT NULL COMMENT '用户名',
+ -- 登录类型,如password、jwt、client_credentials等
+ `login_type` VARCHAR(50) DEFAULT NULL COMMENT '登录类型',
+ -- 失败时间,记录登录失败的时间
+ `failed_time` DATETIME NOT NULL COMMENT '失败时间',
+ -- 失败原因,说明登录失败的具体原因
+ `failed_reason` TEXT DEFAULT NULL COMMENT '失败原因',
+ -- 操作IP地址,记录登录失败的IP地址
+ `ip_address` VARCHAR(50) DEFAULT NULL COMMENT 'IP地址',
+ -- 设备信息,记录登录失败的设备信息
+ `device_info` VARCHAR(500) DEFAULT NULL COMMENT '设备信息',
+ -- 锁定状态,如LOCKED、UNLOCKED
+ `lock_status` VARCHAR(20) NOT NULL DEFAULT 'UNLOCKED' COMMENT '锁定状态',
+ -- 锁定时间,记录登录锁定的时间
+ `lock_time` DATETIME DEFAULT NULL COMMENT '锁定时间',
+ -- 解锁时间,记录登录解锁的时间
+ `unlock_time` DATETIME DEFAULT NULL COMMENT '解锁时间',
+ -- 锁定原因,说明登录锁定的原因
+ `lock_reason` TEXT DEFAULT NULL COMMENT '锁定原因',
+ -- 创建人,记录创建失败登录记录的用户
+ `create_by` VARCHAR(64) DEFAULT NULL COMMENT '创建人',
+ -- 创建时间,记录失败登录记录创建的时间
+ `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
+ -- 主键索引,唯一标识失败登录记录
+ PRIMARY KEY (`failed_id`),
+ -- 普通索引,加速按用户名查询失败登录记录
+ KEY `idx_username` (`username`),
+ -- 普通索引,加速按IP地址查询失败登录记录
+ KEY `idx_ip_address` (`ip_address`),
+ -- 普通索引,加速按失败时间查询失败登录记录
+ KEY `idx_failed_time` (`failed_time`),
+ -- 普通索引,加速按锁定状态查询失败登录记录
+ KEY `idx_lock_status` (`lock_status`),
+ -- 普通索引,加速按租户编号查询失败登录记录
+ KEY `idx_tenant_id` (`tenant_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='失败登录表,记录登录失败尝试,用于登录锁定和风险检测';
+
+-- -----------------------------
+-- 登录统计表 (datai_sf_login_statistics)
+-- -----------------------------
+-- 用途:记录登录统计信息,用于生成报表和分析
+-- 设计考虑:
+-- 1. 支持按时间维度统计
+-- 2. 支持按登录类型统计
+-- 3. 支持按成功/失败状态统计
+-- 4. 支持多租户隔离
+CREATE TABLE `datai_sf_login_statistics` (
+ -- 统计ID,自增主键,唯一标识一条统计记录
+ `stat_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '统计ID',
+ -- 租户编号,支持多租户隔离
+ `tenant_id` VARCHAR(32) DEFAULT NULL COMMENT '租户编号',
+ -- 统计日期,统计数据的日期
+ `stat_date` DATE NOT NULL COMMENT '统计日期',
+ -- 统计小时,统计数据的小时(0-23),用于小时级统计
+ `stat_hour` INT(11) DEFAULT NULL COMMENT '统计小时',
+ -- 登录类型,如oauth2、salesforce_cli、legacy_credential等
+ `login_type` VARCHAR(50) NOT NULL COMMENT '登录类型',
+ -- 成功登录次数
+ `success_count` INT(11) NOT NULL DEFAULT 0 COMMENT '成功次数',
+ -- 失败登录次数
+ `failed_count` INT(11) NOT NULL DEFAULT 0 COMMENT '失败次数',
+ -- 令牌刷新次数
+ `refresh_count` INT(11) NOT NULL DEFAULT 0 COMMENT '刷新次数',
+ -- 令牌吊销次数
+ `revoke_count` INT(11) NOT NULL DEFAULT 0 COMMENT '吊销次数',
+ -- 创建人,记录创建统计记录的用户
+ `create_by` VARCHAR(64) DEFAULT NULL COMMENT '创建人',
+ -- 创建时间,记录统计记录创建的时间
+ `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
+ -- 更新人,记录最后更新统计记录的用户
+ `update_by` VARCHAR(64) DEFAULT NULL COMMENT '更新人',
+ -- 更新时间,记录统计记录最后更新的时间
+ `update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
+ -- 主键索引,唯一标识统计记录
+ PRIMARY KEY (`stat_id`),
+ -- 唯一约束,确保每个统计维度只有一条记录
+ UNIQUE KEY `uk_stat_dimension` (`tenant_id`,`stat_date`,`stat_hour`,`login_type`),
+ -- 普通索引,加速按统计日期查询统计记录
+ KEY `idx_stat_date` (`stat_date`),
+ -- 普通索引,加速按统计小时查询统计记录
+ KEY `idx_stat_hour` (`stat_hour`),
+ -- 普通索引,加速按登录类型查询统计记录
+ KEY `idx_login_type` (`login_type`),
+ -- 普通索引,加速按租户编号查询统计记录
+ KEY `idx_tenant_id` (`tenant_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='登录统计表,记录登录统计信息,用于生成报表和分析';
\ No newline at end of file
diff --git a/datai-scenes/datai-scene-salesforce/datai-salesforce-starter/pom.xml b/datai-scenes/datai-scene-salesforce/datai-salesforce-starter/pom.xml
index 171a1ee2..30b909b8 100644
--- a/datai-scenes/datai-scene-salesforce/datai-salesforce-starter/pom.xml
+++ b/datai-scenes/datai-scene-salesforce/datai-salesforce-starter/pom.xml
@@ -26,6 +26,10 @@
com.datai
datai-salesforce-config
+
+ com.datai
+ datai-salesforce-auth
+
\ No newline at end of file
diff --git a/datai-scenes/datai-scene-salesforce/pom.xml b/datai-scenes/datai-scene-salesforce/pom.xml
index 89b356a6..1afdd49e 100644
--- a/datai-scenes/datai-scene-salesforce/pom.xml
+++ b/datai-scenes/datai-scene-salesforce/pom.xml
@@ -19,6 +19,7 @@
datai-salesforce-common
datai-salesforce-config
datai-salesforce-starter
+ datai-salesforce-auth
@@ -33,6 +34,11 @@
datai-salesforce-config
${datai.version}
+
+ com.datai
+ datai-salesforce-auth
+ ${datai.version}
+