# 架构设计 **本文引用的文件** - [CrmAppApplication.java](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java) - [application.yml](file://crm-app/src/main/resources/application.yml) - [AuthApplication.java](file://crm-auth/src/main/java/com/crm/auth/AuthApplication.java) - [application.yml](file://crm-auth/src/main/resources/application.yml) - [pom.xml](file://pom.xml) - [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java) - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java) - [CorsConfig.java](file://crm-base/src/main/java/com/crm/base/config/CorsConfig.java) - [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java) - [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java) - [SnowflakeIdWorker.java](file://crm-base/src/main/java/com/crm/base/config/SnowflakeIdWorker.java) - [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java) - [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java) - [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java) - [PageResult.java](file://crm-base/src/main/java/com/crm/base/domain/result/PageResult.java) - [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java) - [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [AuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java) - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java) - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) - [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java) - [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java) - [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java) - [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java) - [ThirdPartyAuthClientFactory.java](file://crm-auth/src/main/java/com/crm/auth/service/client/ThirdPartyAuthClientFactory.java) - [DingTalkAuthClient.java](file://crm-auth/src/main/java/com/crm/auth/service/client/DingTalkAuthClient.java) - [ThirdPartyUserInfo.java](file://crm-auth/src/main/java/com/crm/auth/service/client/ThirdPartyUserInfo.java) - [FileApi.java](file://crm-file/src/main/java/com/crm/file/api/FileApi.java) - [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java) - [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java) - [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java) - [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java) - [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java) - [0009-sso-reuses-scan-login-endpoint.md](file://docs/adr/0009-sso-reuses-scan-login-endpoint.md) ## 更新摘要 **所做更改** - 更新了第三方集成模式章节,详细说明单点登录端点复用决策 - 新增了SSO架构设计说明,解释钉钉免登与扫码登录的统一处理机制 - 更新了认证流程图,展示两种登录方式的统一处理路径 - 增强了扩展性设计说明,包含未来JS-SDK支持的规划 ## 目录 1. [引言](#引言) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考量](#性能考量) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 引言 本架构设计文档面向架构师与高级开发者,围绕CRM系统的微服务划分、分层设计原则、组件交互关系与数据流向展开。重点阐述安全架构(认证授权、数据权限)、数据访问层(MyBatis-Plus、分布式ID)、缓存策略(Redis、部门树缓存)、文件存储方案(分片上传、对象存储、在线预览)等关键技术决策。同时给出系统边界定义、第三方集成模式与扩展点设计,并提供架构图表以说明模块间的依赖关系与通信机制。 **更新** 本次更新重点阐述了单点登录(SSO)的架构决策,特别是钉钉免登录场景下复用现有扫码登录端点的设计模式,消除了冗余代码的同时支持多种登录方式。 ## 项目结构 本项目采用多模块Maven工程,按领域与服务进行拆分: - crm-app:应用启动入口与全局配置聚合 - crm-base:公共基础能力(统一异常、通用实体、安全工具、MyBatis-Plus与Redis配置、分布式ID生成等) - crm-auth:认证授权与系统管理域(用户、角色、菜单、部门、数据权限、第三方登录) - crm-file:文件服务(分片上传、断点续传、对象存储、在线预览、清理任务) ```mermaid graph TB subgraph "应用层" APP["crm-app
应用启动"] end subgraph "基础能力" BASE["crm-base
通用配置/安全/工具"] end subgraph "业务服务" AUTH["crm-auth
认证与系统管理"] FILE["crm-file
文件服务"] end APP --> AUTH APP --> FILE AUTH --> BASE FILE --> BASE ``` 图表来源 - [CrmAppApplication.java](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java) - [AuthApplication.java](file://crm-auth/src/main/java/com/crm/auth/AuthApplication.java) - [pom.xml](file://pom.xml) 章节来源 - [CrmAppApplication.java](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java) - [AuthApplication.java](file://crm-auth/src/main/java/com/crm/auth/AuthApplication.java) - [pom.xml](file://pom.xml) ## 核心组件 - 统一响应与分页:Result、PageResult - 通用实体:BaseEntity、OwnedEntity(支持审计字段与数据归属) - 安全上下文:LoginUser、SecurityUtils、DataVisibilityContext - 数据权限:@DataScope注解、DataScopeHelper、拦截器与SQL注入器 - MyBatis-Plus:CRUD增强、自动填充、分页插件 - Redis:缓存与分布式会话支撑 - 分布式ID:雪花算法实现 - 文件服务:分片上传、断点续传、对象存储、在线预览、定时清理 - 第三方认证:工厂模式抽象、统一用户信息模型、组织准入校验 章节来源 - [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java) - [PageResult.java](file://crm-base/src/main/java/com/crm/base/domain/result/PageResult.java) - [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java) - [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java) - [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java) - [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java) - [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java) - [SnowflakeIdWorker.java](file://crm-base/src/main/java/com/crm/base/config/SnowflakeIdWorker.java) - [ThirdPartyAuthClientFactory.java](file://crm-auth/src/main/java/com/crm/auth/service/client/ThirdPartyAuthClientFactory.java) - [ThirdPartyUserInfo.java](file://crm-auth/src/main/java/com/crm/auth/service/client/ThirdPartyUserInfo.java) ## 架构总览 系统采用"网关/应用聚合 + 领域微服务"的分层与解耦模式: - 应用层:统一入口与跨服务编排 - 领域服务:认证授权、文件服务等独立部署 - 基础能力:被各服务复用,保证一致性与可维护性 ```mermaid graph TB Client["客户端"] --> API["API层
控制器"] API --> SVC["服务层
业务编排"] SVC --> SEC["安全层
鉴权/数据权限"] SVC --> DB["数据访问层
MyBatis-Plus"] SVC --> CACHE["缓存层
Redis"] SVC --> EXT["外部集成
第三方登录/文件预览"] DB --> DS["数据库"] CACHE --> RC["Redis集群"] EXT --> OSS["对象存储"] EXT --> VIEW["在线预览服务"] EXT --> THIRD["第三方平台
钉钉OAuth"] ``` 图表来源 - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) - [AuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java) - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java) - [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java) - [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java) - [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java) - [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java) - [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java) - [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java) ## 详细组件分析 ### 认证与安全架构 - 认证流程:客户端提交凭证 → 过滤器校验JWT → 构建登录用户上下文 → 控制器调用服务层完成登录逻辑 → 返回令牌与用户信息 - 授权与数据权限:基于角色的菜单权限与基于注解的数据范围控制,结合SQL注入器动态拼接数据可见性条件 - 第三方登录:通过工厂模式扩展不同平台(如钉钉),统一抽象为第三方认证客户端 **更新** 单点登录(SSO)采用端点复用策略,钉钉免登录与扫码登录共用同一接口,简化了架构设计。 ```mermaid sequenceDiagram participant C as "客户端" participant F as "JwtAuthenticationFilter" participant A as "AuthController" participant S as "AuthServiceImpl" participant T as "TokenService" participant R as "Redis" C->>F : "携带JWT请求" F->>F : "解析并验证Token" F-->>A : "放行并注入Security上下文" A->>S : "登录/刷新Token" S->>T : "生成/更新Token" T->>R : "写入会话/黑名单" T-->>S : "返回Token" S-->>A : "返回结果" A-->>C : "统一响应Result" ``` 图表来源 - [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java) - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) - [AuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java) - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java) - [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java) - [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java) 章节来源 - [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java) - [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java) - [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java) - [AuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java) - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java) - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) #### 数据权限模型 - 注解驱动:@DataScope标注方法或类,声明数据范围级别 - 执行期处理:DataScopeHelper解析当前用户与范围,动态注入SQL过滤条件 - 上下文隔离:DataVisibilityContext在请求链路中传递可见性参数 ```mermaid classDiagram class DataScope { +注解 : 声明数据范围 } class DataScopeHelper { +解析范围() +注入SQL条件() } class DataVisibilityContext { +设置可见性() +获取可见性() } DataScopeHelper --> DataVisibilityContext : "读写上下文" ``` 图表来源 - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) 章节来源 - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) ### 数据访问层设计 - ORM框架:MyBatis-Plus提供CRUD增强、分页、自动填充、条件构造器 - 分布式ID:SnowflakeIdWorker生成唯一主键,避免冲突 - 通用基类:BaseEntity统一审计字段,OwnedEntity扩展数据归属字段 - 配置:注册MetaObjectFillHandler、分页插件、自定义SQL注入器 ```mermaid flowchart TD Start(["进入查询"]) --> BuildQuery["构建查询条件"] BuildQuery --> ApplyScope["应用数据权限条件"] ApplyScope --> Execute["执行SQL(分页/排序)"] Execute --> MapEntity["映射到实体(BaseEntity/OwenedEntity)"] MapEntity --> Return["返回结果集"] ``` 图表来源 - [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java) - [SnowflakeIdWorker.java](file://crm-base/src/main/java/com/crm/base/config/SnowflakeIdWorker.java) - [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java) - [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java) 章节来源 - [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java) - [SnowflakeIdWorker.java](file://crm-base/src/main/java/com/crm/base/config/SnowflakeIdWorker.java) - [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java) - [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java) ### 缓存策略 - 部门树缓存:将部门层级结构缓存至Redis,降低频繁查询压力 - 会话与令牌:TokenService使用Redis维护会话状态与黑名单 - 通用缓存:RedisConfig提供连接池、序列化等基础能力 ```mermaid sequenceDiagram participant S as "服务层" participant D as "DeptTreeCache" participant R as "Redis" S->>D : "获取部门树" D->>R : "读取缓存" alt "命中" R-->>D : "返回缓存数据" D-->>S : "直接返回" else "未命中" D->>D : "查询数据库构建树" D->>R : "写入缓存" D-->>S : "返回数据" end ``` 图表来源 - [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java) - [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java) 章节来源 - [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java) - [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java) ### 文件存储方案 - 分片上传:前端分片、服务端合并、断点续传与会话管理 - 对象存储:MinIO作为底层存储,统一文件元数据与下载接口 - 在线预览:KkFileViewClient对接预览服务,返回预览链接 - 清理任务:定时扫描孤儿分片,释放存储空间 ```mermaid sequenceDiagram participant FE as "前端" participant FC as "FileController" participant FA as "FileApiImpl" participant FS as "FileInfoServiceImpl" participant OSS as "对象存储" participant PV as "预览服务" FE->>FC : "发起分片上传" FC->>FA : "初始化上传会话" FA->>FS : "创建/更新分片记录" loop "分片传输" FE->>FC : "上传分片" FC->>FA : "保存分片到OSS" FA->>FS : "更新分片状态" end FE->>FC : "触发合并" FC->>FA : "合并分片并生成文件信息" FA->>PV : "生成预览链接" FA-->>FE : "返回文件信息与预览地址" ``` 图表来源 - [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java) - [FileApi.java](file://crm-file/src/main/java/com/crm/file/api/FileApi.java) - [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java) - [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java) - [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java) - [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java) 章节来源 - [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java) - [FileApi.java](file://crm-file/src/main/java/com/crm/file/api/FileApi.java) - [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java) - [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java) - [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java) - [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java) ### 第三方集成模式 - 工厂模式:ThirdPartyAuthClientFactory根据类型选择具体客户端 - 统一抽象:ThirdPartyUserInfo标准化第三方用户信息 - 可扩展:新增平台只需实现客户端接口并注册到工厂 - **单点登录优化**:钉钉免登录复用现有扫码登录端点,消除冗余代码 **更新** 单点登录(SSO)架构采用了端点复用策略,钉钉免登录与扫码登录共用 `POST /api/auth/login/dingtalk` 接口。这种设计避免了为免登录场景创建独立的SSO端点,因为两种场景的authCode都通过钉钉 `oauth2/userAccessToken` API换取用户级accessToken,后端处理逻辑完全一致。 ```mermaid sequenceDiagram participant Browser as "浏览器" participant DingTalk as "钉钉平台" participant CRM as "CRM后端" participant Auth as "认证服务" participant Client as "钉钉客户端" Note over Browser,DingTalk : 扫码登录流程 Browser->>DingTalk : "打开扫码页面" DingTalk-->>Browser : "返回二维码" Browser->>DingTalk : "用户扫码确认" DingTalk-->>Browser : "返回authCode" Browser->>CRM : "POST /api/auth/login/dingtalk?authCode=xxx" CRM->>Auth : "调用登录服务" Auth->>Client : "getUserInfo(authCode)" Client->>DingTalk : "换取accessToken" DingTalk-->>Client : "返回accessToken" Client->>DingTalk : "查询用户信息" DingTalk-->>Client : "返回用户信息" Client-->>Auth : "返回ThirdPartyUserInfo" Auth->>Auth : "用户匹配/注册/绑定身份" Auth-->>CRM : "返回登录结果" CRM-->>Browser : "返回JWT Token" Note over Browser,DingTalk : 免登录流程复用同一端点 Browser->>DingTalk : "已登录态访问CRM" DingTalk-->>Browser : "自动重定向带authCode" Browser->>CRM : "POST /api/auth/login/dingtalk?authCode=xxx" Note over CRM : "处理逻辑与扫码登录完全相同" ``` 图表来源 - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) - [DingTalkAuthClient.java](file://crm-auth/src/main/java/com/crm/auth/service/client/DingTalkAuthClient.java) - [ThirdPartyAuthClientFactory.java](file://crm-auth/src/main/java/com/crm/auth/service/client/ThirdPartyAuthClientFactory.java) - [0009-sso-reuses-scan-login-endpoint.md](file://docs/adr/0009-sso-reuses-scan-login-endpoint.md) 章节来源 - [ThirdPartyAuthClientFactory.java](file://crm-auth/src/main/java/com/crm/auth/service/client/ThirdPartyAuthClientFactory.java) - [DingTalkAuthClient.java](file://crm-auth/src/main/java/com/crm/auth/service/client/DingTalkAuthClient.java) - [ThirdPartyUserInfo.java](file://crm-auth/src/main/java/com/crm/auth/service/client/ThirdPartyUserInfo.java) - [0009-sso-reuses-scan-login-endpoint.md](file://docs/adr/0009-sso-reuses-scan-login-endpoint.md) ### 单点登录架构设计 **新增** 基于ADR-0009的决策,系统采用了统一的第三方认证架构: - **端点复用策略**:钉钉免登录与扫码登录共用 `POST /api/auth/login/dingtalk` 接口 - **统一处理逻辑**:两种场景的authCode都通过相同的钉钉API换取用户级accessToken - **零后端改动**:前端自行管理OAuth重定向URL和clientId,后端无需区分登录来源 - **扩展性考虑**:未来如需支持钉钉桌面客户端内H5免登(JS-SDK),需新增签名端点 ```mermaid classDiagram class ThirdPartyAuthClient { <> +getType() IdentityTypeEnum +getUserInfo(authCode) ThirdPartyUserInfo +isOrgMember(user) boolean } class DingTalkAuthClient { +fetchUserAccessToken(code) String +fetchUserInfo(token) ThirdPartyUserInfo +getCorpAccessToken() String +requestTokenApi(code) String +requestUserInfoApi(token) String +requestCorpTokenApi() String +requestGetByUnionIdApi(token, unionId) String } class ThirdPartyAuthClientFactory { +getClient(type) ThirdPartyAuthClient } class AuthServiceImpl { +login(type, authCode) LoginResultDTO +doLoginInTx(type, thirdUser) AuthUser +preCheckOrgMembership(type, user, client) void } ThirdPartyAuthClient <|.. DingTalkAuthClient ThirdPartyAuthClientFactory --> ThirdPartyAuthClient AuthServiceImpl --> ThirdPartyAuthClientFactory ``` 图表来源 - [DingTalkAuthClient.java](file://crm-auth/src/main/java/com/crm/auth/service/client/DingTalkAuthClient.java) - [ThirdPartyAuthClientFactory.java](file://crm-auth/src/main/java/com/crm/auth/service/client/ThirdPartyAuthClientFactory.java) - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java) 章节来源 - [DingTalkAuthClient.java](file://crm-auth/src/main/java/com/crm/auth/service/client/DingTalkAuthClient.java) - [ThirdPartyAuthClientFactory.java](file://crm-auth/src/main/java/com/crm/auth/service/client/ThirdPartyAuthClientFactory.java) - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java) - [0009-sso-reuses-scan-login-endpoint.md](file://docs/adr/0009-sso-reuses-scan-login-endpoint.md) ## 依赖关系分析 - 模块耦合:crm-app仅负责启动与聚合;crm-auth与crm-file均依赖crm-base - 内部依赖:auth服务内service→mapper→entity的单向依赖;file服务内controller→api→service→mapper - 外部依赖:Redis、对象存储、第三方登录平台 ```mermaid graph LR APP["crm-app"] --> AUTH["crm-auth"] APP --> FILE["crm-file"] AUTH --> BASE["crm-base"] FILE --> BASE AUTH --> REDIS["Redis"] FILE --> OSS["对象存储"] AUTH --> THIRD["第三方登录平台"] ``` 图表来源 - [pom.xml](file://pom.xml) - [CrmAppApplication.java](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java) - [AuthApplication.java](file://crm-auth/src/main/java/com/crm/auth/AuthApplication.java) 章节来源 - [pom.xml](file://pom.xml) - [CrmAppApplication.java](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java) - [AuthApplication.java](file://crm-auth/src/main/java/com/crm/auth/AuthApplication.java) ## 性能考量 - 数据访问优化:合理使用分页、索引与条件构造器,避免全表扫描;利用MyBatis-Plus批量操作减少往返 - 缓存策略:热点数据(如部门树、字典)优先缓存;注意缓存穿透、雪崩与一致性策略 - 分布式ID:雪花算法避免中心节点瓶颈,提升写入吞吐 - 文件上传:分片并发上传与断点续传提升大文件体验;合并后及时清理临时分片 - 安全开销:JWT无状态减少会话存储压力;敏感操作加限流与幂等保护 - **第三方调用优化**:钉钉企业级token缓存、组织准入校验事务外执行,避免长时间占用数据库连接 [本节为通用指导,不直接分析具体文件] ## 故障排查指南 - 统一异常处理:GlobalExceptionHandlerAdvice集中捕获业务与系统异常,返回标准错误码与消息 - 常见错误定位:检查日志中的TraceId;核对Redis连接与对象存储配置;确认JWT签名与过期时间 - 数据权限问题:核查@DataScope注解与上下文是否正确设置;检查SQL注入器是否生效 - 文件上传失败:查看分片完整性与合并任务;确认对象存储桶权限与网络连通性 - **第三方登录问题**:检查钉钉配置(client-id/secret)、网络连通性、token缓存状态、组织准入校验结果 章节来源 - [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java) - [application.yml](file://crm-app/src/main/resources/application.yml) - [application.yml](file://crm-auth/src/main/resources/application.yml) ## 结论 本架构以清晰的模块边界与分层设计为基础,通过安全、数据访问、缓存与文件服务的专项设计,满足CRM系统在认证授权、数据权限、高可用与可扩展方面的需求。**特别地,单点登录架构通过端点复用策略实现了简洁高效的第三方认证处理**。未来可在网关层引入更细粒度的路由与限流,在服务间引入事件总线以提升异步处理能力,并持续完善监控与可观测性体系。 [本节为总结性内容,不直接分析具体文件] ## 附录 - 系统边界定义:认证与系统管理(crm-auth)、文件服务(crm-file)、基础能力(crm-base)、应用聚合(crm-app) - 扩展点设计:第三方登录客户端工厂、数据权限注解、文件上传处理器、缓存项命名规范 - 配置要点:跨域、Jackson序列化、Knife4j文档、定时任务属性、雪花ID参数 - **SSO设计决策**:钉钉免登录复用扫码登录端点,消除冗余代码,支持未来JS-SDK扩展 [本节为补充信息,不直接分析具体文件]