feat: 系统全面优化 - 设备管理/登录日志导出/性能监控/设置页面

后端:
- 新增全局设备管理 API(DeviceHandler.GetAllDevices)
- 新增登录日志导出功能(LogHandler.ExportLoginLogs, CSV/XLSX)
- 新增设置服务(SettingsService)和设置页面 API
- 设备管理支持多条件筛选(状态/信任状态/关键词)
- 登录日志支持流式导出防 OOM
- 操作日志支持按方法/时间范围搜索
- 主题配置服务(ThemeService)
- 增强监控健康检查(Prometheus metrics + SLO)
- 移除旧 ratelimit.go(已迁移至 robustness)
- 修复 SocialAccount NULL 扫描问题
- 新增 API 契约测试、Handler 测试、Settings 测试

前端:
- 新增管理员设备管理页面(DevicesPage)
- 新增管理员登录日志导出功能
- 新增系统设置页面(SettingsPage)
- 设备管理支持筛选和分页
- 增强 HTTP 响应类型

测试:
- 业务逻辑测试 68 个(含并发 CONC_001~003)
- 规模测试 16 个(P99 百分位统计)
- E2E 测试、集成测试、契约测试
- 性能基准测试、鲁棒性测试

全面测试通过(38 个测试包)
This commit is contained in:
2026-04-07 12:08:16 +08:00
parent 8655b39b03
commit 5ca3633be4
36 changed files with 4552 additions and 134 deletions

View File

@@ -3,6 +3,7 @@ package service
import (
"context"
"errors"
"regexp"
"github.com/user-management-system/internal/domain"
"github.com/user-management-system/internal/repository"
@@ -48,6 +49,11 @@ type UpdateThemeRequest struct {
// CreateTheme 创建主题
func (s *ThemeService) CreateTheme(ctx context.Context, req *CreateThemeRequest) (*domain.ThemeConfig, error) {
// 安全检查:禁止在 CustomCSS/CustomJS 中包含危险模式
if err := validateCustomCSSJS(req.CustomCSS, req.CustomJS); err != nil {
return nil, err
}
// 检查主题名称是否已存在
existing, err := s.themeRepo.GetByName(ctx, req.Name)
if err == nil && existing != nil {
@@ -84,6 +90,11 @@ func (s *ThemeService) CreateTheme(ctx context.Context, req *CreateThemeRequest)
// UpdateTheme 更新主题
func (s *ThemeService) UpdateTheme(ctx context.Context, id int64, req *UpdateThemeRequest) (*domain.ThemeConfig, error) {
// 安全检查:禁止在 CustomCSS/CustomJS 中包含危险模式
if err := validateCustomCSSJS(req.CustomCSS, req.CustomJS); err != nil {
return nil, err
}
theme, err := s.themeRepo.GetByID(ctx, id)
if err != nil {
return nil, errors.New("主题不存在")
@@ -204,3 +215,43 @@ func (s *ThemeService) clearDefaultThemes(ctx context.Context) error {
}
return nil
}
// validateCustomCSSJS 检查 CustomCSS 和 CustomJS 是否包含危险 XSS 模式
// 这不是完全净化,而是拒绝明显可造成 XSS 的模式
func validateCustomCSSJS(css, js string) error {
// 危险模式列表
dangerousPatterns := []struct {
pattern *regexp.Regexp
message string
}{
// Script 标签
{regexp.MustCompile(`(?i)<script[^>]*>.*?</script>`), "CustomJS 禁止包含 <script> 标签"},
{regexp.MustCompile(`(?i)javascript\s*:`), "CustomJS 禁止使用 javascript: 协议"},
// 事件处理器
{regexp.MustCompile(`(?i)on\w+\s*=`), "CustomJS 禁止使用事件处理器 (如 onerror, onclick)"},
// Data URL
{regexp.MustCompile(`(?i)data\s*:\s*text/html`), "禁止使用 data: URL 嵌入 HTML"},
// CSS expression (IE)
{regexp.MustCompile(`(?i)expression\s*\(`), "CustomCSS 禁止使用 CSS expression"},
// CSS 中的 javascript
{regexp.MustCompile(`(?i)url\s*\(\s*['"]?\s*javascript:`), "CustomCSS 禁止使用 javascript: URL"},
// 嵌入的 <style> 标签
{regexp.MustCompile(`(?i)<style[^>]*>.*?</style>`), "CustomCSS 禁止包含 <style> 标签"},
}
// 检查 JS
for _, p := range dangerousPatterns {
if p.pattern.MatchString(js) {
return errors.New(p.message)
}
}
// 检查 CSS
for _, p := range dangerousPatterns {
if p.pattern.MatchString(css) {
return errors.New(p.message)
}
}
return nil
}