- 描述整体基于ASP.NET Core的分层架构与领域驱动设计 - 详细说明表现层、视图模型层、配置层和基础设施层职责 - 介绍用户认证、OAuth2授权码与令牌颁发的数据流过程 - 抽象说明用户与租户、声明和授权实体设计 - 说明应用启动入口和关键HTTP端点 - 列出错误处理策略和跨领域关注点(日志、追踪、安全) docs(concerns): 新增代码库问题与关注点分析文档 - 汇总并详述安全漏洞如配置文件泄露、Cookie策略不当 - 记录技术债务包括缺乏单元测试、依赖注入不统一等 - 罗列性能问题和具体代码缺陷 - 给出优先级明确的修复建议和改进措施 - 涵盖架构设计问题和依赖兼容性风险 - 说明测试覆盖缺口及高风险未测试区域 docs(conventions): 新增编码约定与规范文档 - 明确文件、类、方法、变量等命名规则 - 规范代码风格包括命名空间、主构造函数使用 - 制定日志记录、审计日志和依赖注入的标准 - 规定控制器路由、异步模式和错误处理方式 - 说明DTO命名及特性使用规范 - 描述配置管理、注释规范及常用代码注释样例 docs(integrations): 添加外部系统集成文档 - 介绍数据库连接和PostgreSQL客户端库版本 - 描述身份认证与授权服务及默认用户信息 - 说明可观测性方案及OpenTelemetry组件 - 涵盖容器化部署相关Docker与Kubernetes配置 - 说明CI/CD流水线触发条件与构建流程 - 列出环境变量需求和主要API端点 - 强调生产环境密钥管理与安全存储机制
538 lines
13 KiB
Markdown
538 lines
13 KiB
Markdown
# 代码库问题与关注点
|
||
|
||
**分析日期:** 2026-02-28
|
||
|
||
---
|
||
|
||
## 一、严重安全问题
|
||
|
||
### 1.1 配置文件泄露敏感凭证
|
||
|
||
**问题描述:** `appsettings.json` 包含明文数据库密码和 JWT 密钥。
|
||
|
||
**文件位置:** `src/appsettings.json`
|
||
|
||
**泄露内容:**
|
||
```json
|
||
"ConnectionStrings": {
|
||
"DefaultConnection": "Host=81.68.223.70;Port=15432;Database=fengling_auth;Username=movingsam;Password=sl52788542"
|
||
},
|
||
"Jwt": {
|
||
"Secret": "FenglingAuthSecretKey2024!ChangeThisInProduction!"
|
||
}
|
||
```
|
||
|
||
**影响:**
|
||
- 数据库凭据完全暴露,包括用户名、密码、主机地址和端口
|
||
- JWT 密钥硬编码在配置文件中,攻击者可用其伪造令牌
|
||
- 若此文件被提交到版本控制系统,将造成严重安全漏洞
|
||
|
||
**修复建议:**
|
||
- 立即将敏感信息迁移至环境变量或密钥保管库
|
||
- 使用 ASP.NET Core 的密钥管理功能(`dotnet user-secrets`)
|
||
- 在生产环境中使用 Azure Key Vault、AWS Secrets Manager 等
|
||
- 创建 `appsettings.Production.json` 并通过环境变量加载配置
|
||
|
||
---
|
||
|
||
### 1.2 Cookie 安全策略配置不当
|
||
|
||
**问题描述:** 认证 Cookie 配置为非安全策略。
|
||
|
||
**文件位置:** `src/Program.cs` 第 43-44 行
|
||
|
||
```csharp
|
||
options.Cookie.SecurePolicy = CookieSecurePolicy.None;
|
||
options.Cookie.SameSite = SameSiteMode.Lax;
|
||
```
|
||
|
||
**影响:**
|
||
- `CookieSecurePolicy.None` 允许 Cookie 通过非 HTTPS 连接传输
|
||
- `SameSiteMode.Lax` 无法完全防止 CSRF 攻击
|
||
- 用户凭证可能在网络传输中被截获
|
||
|
||
**修复建议:**
|
||
```csharp
|
||
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
|
||
options.Cookie.SameSite = SameSiteMode.Strict;
|
||
options.Cookie.HttpOnly = true;
|
||
```
|
||
|
||
---
|
||
|
||
### 1.3 访问令牌未加密
|
||
|
||
**问题描述:** OpenIddict 配置禁用了访问令牌加密。
|
||
|
||
**文件位置:** `src/Configuration/OpenIddictSetup.cs` 第 64 行
|
||
|
||
```csharp
|
||
options.DisableAccessTokenEncryption();
|
||
```
|
||
|
||
**影响:**
|
||
- 访问令牌以明文形式传输,任何中间人都能读取令牌内容
|
||
- 攻击者可窃取令牌并冒充合法用户
|
||
|
||
**修复建议:**
|
||
- 生产环境必须启用令牌加密
|
||
- 使用有效的加密证书而非开发证书
|
||
|
||
---
|
||
|
||
### 1.4 CORS 允许所有来源
|
||
|
||
**问题描述:** CORS 配置允许任意来源的跨域请求。
|
||
|
||
**文件位置:** `src/Program.cs` 第 102-109 行
|
||
|
||
```csharp
|
||
app.UseCors(x =>
|
||
{
|
||
x.SetIsOriginAllowed(origin => true)
|
||
.AllowAnyHeader()
|
||
.AllowAnyMethod()
|
||
.AllowCredentials()
|
||
.Build();
|
||
});
|
||
```
|
||
|
||
**影响:**
|
||
- 任何网站都能向此 API 发起跨域请求
|
||
- 极大增加 CSRF 和数据泄露风险
|
||
|
||
**修复建议:**
|
||
- 明确配置允许的来源列表
|
||
- 使用环境变量控制允许的域名
|
||
|
||
---
|
||
|
||
### 1.5 开发证书用于生产环境
|
||
|
||
**问题描述:** OpenIddict 使用开发环境证书进行签名和加密。
|
||
|
||
**文件位置:** `src/Configuration/OpenIddictSetup.cs` 第 61-62 行
|
||
|
||
```csharp
|
||
options.AddDevelopmentEncryptionCertificate()
|
||
.AddDevelopmentSigningCertificate();
|
||
```
|
||
|
||
**影响:**
|
||
- 开发证书的私钥是公开的,攻击者可伪造令牌
|
||
- 严重威胁生产环境安全
|
||
|
||
**修复建议:**
|
||
- 生产环境使用正式的 SSL/TLS 证书
|
||
- 使用 Azure Key Vault 或类似服务存储证书
|
||
|
||
---
|
||
|
||
## 二、技术债务
|
||
|
||
### 2.1 完全没有单元测试
|
||
|
||
**问题描述:** 代码库中不存在任何测试文件。
|
||
|
||
**文件位置:** 整个项目
|
||
|
||
**影响:**
|
||
- 无法确保代码质量
|
||
- 重构风险极高,容易引入 bug
|
||
- 难以验证边界条件和错误处理
|
||
|
||
**修复建议:**
|
||
- 引入 xUnit 或 NUnit 测试框架
|
||
- 为所有 Controller 编写单元测试
|
||
- 为关键业务逻辑(Token 颁发、用户管理等)编写集成测试
|
||
- 目标覆盖率应达到 70% 以上
|
||
|
||
---
|
||
|
||
### 2.2 使用 .NET 10.0
|
||
|
||
**问题描述:** 项目目标框架为 .NET 10.0。
|
||
|
||
**文件位置:** `src/Fengling.AuthService.csproj` 第 3 行
|
||
|
||
```xml
|
||
<TargetFramework>net10.0</TargetFramework>
|
||
```
|
||
|
||
**影响:**
|
||
- .NET 10.0 目前可能为预览版或早期版本
|
||
- 稳定性存在风险,缺乏长期支持
|
||
- 依赖包兼容性问题
|
||
|
||
**修复建议:**
|
||
- 生产环境应使用 LTS(长期支持)版本(如 .NET 8.0)
|
||
- 密切关注 .NET 10.0 的正式发布和稳定性评估
|
||
|
||
---
|
||
|
||
### 2.3 审计日志逻辑重复
|
||
|
||
**问题描述:** 审计日志创建逻辑在多个控制器中重复实现。
|
||
|
||
**受影响文件:**
|
||
- `src/Controllers/UsersController.cs` - `CreateAuditLog` 方法
|
||
- `src/Controllers/RolesController.cs` - `CreateAuditLog` 方法
|
||
- `src/Controllers/TenantsController.cs` - `CreateAuditLog` 方法
|
||
|
||
**影响:**
|
||
- 代码重复,维护困难
|
||
- 行为不一致风险
|
||
- 违反 DRY 原则
|
||
|
||
**修复建议:**
|
||
- 提取为独立的审计日志服务
|
||
- 使用 MediatR 管道行为统一处理
|
||
- 创建审计日志特性的 AOP 方案
|
||
|
||
---
|
||
|
||
### 2.4 不一致的依赖注入风格
|
||
|
||
**问题描述:** 控制器同时使用两种不同的依赖注入方式。
|
||
|
||
**文件位置:**
|
||
- 构造函数注入(传统方式):`src/Controllers/RolesController.cs`
|
||
- Primary Constructor 注入(记录式):`src/Controllers/UsersController.cs`
|
||
|
||
**示例对比:**
|
||
|
||
传统方式(RolesController):
|
||
```csharp
|
||
public class RolesController : ControllerBase
|
||
{
|
||
private readonly PlatformDbContext _context;
|
||
|
||
public RolesController(PlatformDbContext context)
|
||
{
|
||
_context = context;
|
||
}
|
||
}
|
||
```
|
||
|
||
Primary Constructor 方式(UsersController):
|
||
```csharp
|
||
public class UsersController(
|
||
UserManager<ApplicationUser> userManager,
|
||
RoleManager<ApplicationRole> roleManager,
|
||
ILogger<UsersController> logger,
|
||
PlatformDbContext platformDbContext)
|
||
: ControllerBase
|
||
```
|
||
|
||
**影响:**
|
||
- 代码风格不统一
|
||
- 增加新人学习成本
|
||
|
||
**修复建议:**
|
||
- 统一采用 Primary Constructor 方式(ASP.NET Core 8.0+ 推荐)
|
||
- 或统一使用传统构造函数注入方式
|
||
|
||
---
|
||
|
||
## 三、已知缺陷
|
||
|
||
### 3.1 未实现的接口方法
|
||
|
||
**问题描述:** 某些接口返回硬编码或空值。
|
||
|
||
**文件位置:** `src/Controllers/TenantsController.cs` 第 171-192 行
|
||
|
||
```csharp
|
||
[HttpGet("{tenantId}/settings")]
|
||
public async Task<ActionResult<TenantSettings>> GetTenantSettings(long tenantId)
|
||
{
|
||
// ...
|
||
var settings = new TenantSettings
|
||
{
|
||
AllowRegistration = false,
|
||
AllowedEmailDomains = "",
|
||
DefaultRoleId = null,
|
||
PasswordPolicy = new List<string> { "requireNumber", "requireLowercase" },
|
||
MinPasswordLength = 8,
|
||
SessionTimeout = 120,
|
||
};
|
||
|
||
return Ok(settings);
|
||
}
|
||
```
|
||
|
||
**影响:**
|
||
- 租户设置无法持久化
|
||
- 配置变更不生效
|
||
|
||
**修复建议:**
|
||
- 创建 TenantSettings 实体
|
||
- 实现 CRUD 操作
|
||
- 与租户配置表关联
|
||
|
||
---
|
||
|
||
### 3.2 Profile 接口重定向
|
||
|
||
**问题描述:** Profile 和 Settings 路由指向未实现的方法。
|
||
|
||
**文件位置:** `src/Controllers/AccountController.cs` 第 111-117 行
|
||
|
||
```csharp
|
||
[HttpGet("profile")]
|
||
[HttpGet("settings")]
|
||
[HttpGet("~/connect/logout")]
|
||
public IActionResult NotImplemented()
|
||
{
|
||
return RedirectToAction("Index", "Dashboard");
|
||
}
|
||
```
|
||
|
||
**影响:**
|
||
- 用户访问个人资料页面时被重定向
|
||
- 功能缺失,用户体验差
|
||
|
||
**修复建议:**
|
||
- 实现完整的个人资料页面
|
||
- 允许用户查看和修改基本信息
|
||
|
||
---
|
||
|
||
## 四、性能问题
|
||
|
||
### 4.1 N+1 查询问题
|
||
|
||
**问题描述:** 列表接口在循环中执行数据库查询。
|
||
|
||
**文件位置:** `src/Controllers/RolesController.cs` 第 63-78 行
|
||
|
||
```csharp
|
||
foreach (var role in roles)
|
||
{
|
||
var users = await _userManager.GetUsersInRoleAsync(role.Name!);
|
||
result.Add(new
|
||
{
|
||
// ...
|
||
userCount = users.Count,
|
||
// ...
|
||
});
|
||
}
|
||
```
|
||
|
||
**影响:**
|
||
- 假设有 N 个角色,将执行 1+N 次数据库查询
|
||
- 角色数量增加时,性能呈线性下降
|
||
- 数据库负载显著增加
|
||
|
||
**修复建议:**
|
||
- 使用单一查询获取所有角色及其用户数
|
||
- 通过 JOIN 或子查询聚合计数
|
||
|
||
---
|
||
|
||
### 4.2 内存分页问题
|
||
|
||
**问题描述:** OAuth 客户端列表先将所有数据加载到内存,再进行分页。
|
||
|
||
**文件位置:** `src/Controllers/OAuthClientsController.cs` 第 31-86 行
|
||
|
||
```csharp
|
||
var applications = _applicationManager.ListAsync();
|
||
var clientList = new List<object>();
|
||
|
||
await foreach (var application in applications)
|
||
{
|
||
// 处理每个应用...
|
||
clientList.Add(new { ... });
|
||
}
|
||
|
||
var sortedClients = clientList
|
||
.OrderByDescending(c => (c as dynamic).clientId)
|
||
.Skip((page - 1) * pageSize)
|
||
.Take(pageSize)
|
||
.ToList();
|
||
```
|
||
|
||
**影响:**
|
||
- 客户端数量增加时,内存占用大幅增长
|
||
- 首次加载缓慢
|
||
- 无法处理大量客户端场景
|
||
|
||
**修复建议:**
|
||
- 使用数据库层面的分页(EF Core 的 Skip/Take)
|
||
- 实现服务端分页而非内存分页
|
||
|
||
---
|
||
|
||
### 4.3 缺少数据库索引
|
||
|
||
**问题描述:** 频繁查询的字段可能缺少索引。
|
||
|
||
**涉及字段:**
|
||
- `Users.UserName` - 登录查询
|
||
- `Users.TenantInfo.TenantId` - 租户隔离查询
|
||
- `AuditLogs.CreatedAt` - 日志查询
|
||
- `AccessLogs.CreatedAt` - 访问日志查询
|
||
|
||
**影响:**
|
||
- 查询性能随数据量增加而下降
|
||
- 大表全表扫描风险
|
||
|
||
**修复建议:**
|
||
- 分析慢查询日志
|
||
- 为常用查询字段添加索引
|
||
- 使用 EF Core 的 Fluent API 配置索引
|
||
|
||
---
|
||
|
||
## 五、架构与设计问题
|
||
|
||
### 5.1 异常处理作为流程控制
|
||
|
||
**问题描述:** 使用异常抛出处理正常业务流程。
|
||
|
||
**文件位置:** `src/Controllers/AuthorizationController.cs` 多处
|
||
|
||
```csharp
|
||
var request = HttpContext.GetOpenIddictServerRequest() ??
|
||
throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");
|
||
|
||
var user = await userManager.GetUserAsync(User) ??
|
||
throw new InvalidOperationException("The user details cannot be retrieved.");
|
||
```
|
||
|
||
**影响:**
|
||
- 异常处理开销大,性能差
|
||
- 代码可读性差
|
||
- 混淆业务逻辑和错误处理
|
||
|
||
**修复建议:**
|
||
- 使用空值合并和空值检查
|
||
- 返回适当的 HTTP 状态码(如 400、401)
|
||
- 使用 `ActionResult<T>` 模式
|
||
|
||
---
|
||
|
||
### 5.2 租户隔离不完整
|
||
|
||
**问题描述:** 某些查询未正确应用租户隔离。
|
||
|
||
**文件位置:** `src/Controllers/UsersController.cs` 第 32-47 行
|
||
|
||
```csharp
|
||
var query = platformDbContext.Users.AsQueryable();
|
||
|
||
if (!string.IsNullOrEmpty(userName))
|
||
{
|
||
query = query.Where(u => u.UserName!.Contains(userName));
|
||
}
|
||
// ...
|
||
```
|
||
|
||
**影响:**
|
||
- 管理员可能查看所有租户的数据
|
||
- 租户数据泄露风险
|
||
|
||
**修复建议:**
|
||
- 创建租户过滤的基类或中间件
|
||
- 在所有查询中自动应用租户 ID 过滤
|
||
- 使用 EF Core 的全局查询过滤器
|
||
|
||
---
|
||
|
||
### 5.3 缺少 API 版本控制
|
||
|
||
**问题描述:** API 端点没有版本控制机制。
|
||
|
||
**影响:**
|
||
- 无法平滑升级 API
|
||
- 客户端兼容性问题
|
||
- 难以废弃旧版 API
|
||
|
||
**修复建议:**
|
||
- 实现 API 版本控制(URL 路径或 Header)
|
||
- 使用 `Microsoft.AspNetCore.Mvc.Versioning`
|
||
- 文档化各版本差异
|
||
|
||
---
|
||
|
||
## 六、依赖与兼容性
|
||
|
||
### 6.1 依赖外部包版本风险
|
||
|
||
**问题描述:** 项目依赖可能存在版本兼容性问题。
|
||
|
||
**关键依赖:**
|
||
- `OpenIddict.AspNetCore` - OAuth/OIDC 实现
|
||
- `Fengling.Platform.Infrastructure` - 内部共享库
|
||
- `NetCorePal.Extensions.AspNetCore` - 扩展库
|
||
|
||
**风险:**
|
||
- 依赖更新可能导致破坏性变更
|
||
- 内部包版本不同步问题
|
||
|
||
**修复建议:**
|
||
- 锁定依赖版本
|
||
- 定期审查依赖更新
|
||
- 建立依赖升级测试流程
|
||
|
||
---
|
||
|
||
## 七、测试覆盖缺口
|
||
|
||
### 7.1 高风险未测试区域
|
||
|
||
| 区域 | 文件位置 | 风险 |
|
||
|------|----------|------|
|
||
| 身份验证流程 | `TokenController.cs` | 令牌颁发、刷新 |
|
||
| 用户管理 | `UsersController.cs` | 用户创建、密码重置 |
|
||
| 授权逻辑 | `AuthorizationController.cs` | OAuth 授权流程 |
|
||
| 租户隔离 | 多个 Controller | 数据泄露风险 |
|
||
|
||
### 7.2 缺失的测试类型
|
||
|
||
- **单元测试:** 业务逻辑、验证逻辑
|
||
- **集成测试:** 数据库交互、API 端点
|
||
- **安全测试:** 认证流程、权限检查
|
||
- **性能测试:** 大数据量场景
|
||
|
||
---
|
||
|
||
## 八、优先级修复建议
|
||
|
||
### 高优先级(立即处理)
|
||
|
||
1. **移除 `appsettings.json` 中的敏感信息**
|
||
- 迁移到环境变量或密钥保管库
|
||
- 轮换已泄露的密码和密钥
|
||
|
||
2. **启用 Cookie 安全策略**
|
||
- 改为 `SecurePolicy.Always`
|
||
- 启用 HttpOnly 和 SameSite=Strict
|
||
|
||
3. **启用访问令牌加密**
|
||
- 移除 `DisableAccessTokenEncryption()`
|
||
- 配置生产证书
|
||
|
||
4. **修复 CORS 配置**
|
||
- 限制允许的来源列表
|
||
|
||
### 中优先级(近期处理)
|
||
|
||
1. **添加单元测试框架和基础测试**
|
||
2. **修复 N+1 查询问题**
|
||
3. **实现内存分页优化**
|
||
4. **统一依赖注入风格**
|
||
5. **实现租户隔离的全局过滤**
|
||
|
||
### 低优先级(长期规划)
|
||
|
||
1. **升级到 .NET LTS 版本**
|
||
2. **提取审计日志服务**
|
||
3. **实现 API 版本控制**
|
||
4. **完善租户设置功能**
|
||
|
||
---
|
||
|
||
*问题审计完成*
|