fix: 生产安全修复 + Go SDK + CAS SSO框架
安全修复: - CRITICAL: SSO重定向URL注入漏洞 - 修复redirect_uri白名单验证 - HIGH: SSO ClientSecret未验证 - 使用crypto/subtle.ConstantTimeCompare验证 - HIGH: 邮件验证码熵值过低(3字节) - 提升到6字节(48位熵) - HIGH: 短信验证码熵值过低(4字节) - 提升到6字节 - HIGH: Goroutine使用已取消上下文 - auth_email.go使用独立context+超时 - HIGH: SQL LIKE查询注入风险 - permission/role仓库使用escapeLikePattern 新功能: - Go SDK: sdk/go/user-management/ 完整SDK实现 - CAS SSO框架: internal/auth/cas.go CAS协议支持 其他: - L1Cache实例问题修复 - AuthMiddleware共享l1Cache - 设备指纹XSS防护 - 内存存储替代localStorage - 响应格式协议中间件 - 导出无界查询修复
This commit is contained in:
@@ -99,6 +99,8 @@ func setupRealServer(t *testing.T) (*httptest.Server, func()) {
|
||||
captchaSvc := service.NewCaptchaService(cacheManager)
|
||||
totpSvc := service.NewTOTPService(userRepo)
|
||||
webhookSvc := service.NewWebhookService(db)
|
||||
exportSvc := service.NewExportService(userRepo, roleRepo)
|
||||
statsSvc := service.NewStatsService(userRepo, loginLogRepo)
|
||||
|
||||
authH := handler.NewAuthHandler(authSvc)
|
||||
userH := handler.NewUserHandler(userSvc)
|
||||
@@ -111,9 +113,11 @@ func setupRealServer(t *testing.T) (*httptest.Server, func()) {
|
||||
totpH := handler.NewTOTPHandler(authSvc, totpSvc)
|
||||
webhookH := handler.NewWebhookHandler(webhookSvc)
|
||||
smsH := handler.NewSMSHandler()
|
||||
exportH := handler.NewExportHandler(exportSvc)
|
||||
statsH := handler.NewStatsHandler(statsSvc)
|
||||
|
||||
rateLimitMW := middleware.NewRateLimitMiddleware(config.RateLimitConfig{})
|
||||
authMW := middleware.NewAuthMiddleware(jwtManager, userRepo, userRoleRepo, roleRepo, rolePermissionRepo, permissionRepo)
|
||||
authMW := middleware.NewAuthMiddleware(jwtManager, userRepo, userRoleRepo, roleRepo, rolePermissionRepo, permissionRepo, l1Cache)
|
||||
authMW.SetCacheManager(cacheManager)
|
||||
opLogMW := middleware.NewOperationLogMiddleware(operationLogRepo)
|
||||
ipFilterMW := middleware.NewIPFilterMiddleware(security.NewIPFilter(), middleware.IPFilterConfig{})
|
||||
@@ -122,7 +126,7 @@ func setupRealServer(t *testing.T) (*httptest.Server, func()) {
|
||||
authH, userH, roleH, permH, deviceH, logH,
|
||||
authMW, rateLimitMW, opLogMW,
|
||||
pwdResetH, captchaH, totpH, webhookH,
|
||||
ipFilterMW, nil, nil, smsH, nil, nil, nil,
|
||||
ipFilterMW, exportH, statsH, smsH, nil, nil, nil,
|
||||
)
|
||||
engine := r.Setup()
|
||||
|
||||
@@ -413,7 +417,32 @@ func doGet(t *testing.T, url string, token string) *http.Response {
|
||||
func decodeJSON(t *testing.T, body io.ReadCloser, v interface{}) {
|
||||
t.Helper()
|
||||
defer body.Close()
|
||||
if err := json.NewDecoder(body).Decode(v); err != nil {
|
||||
raw, err := io.ReadAll(body)
|
||||
if err != nil {
|
||||
t.Logf("读取响应 body 失败: %v(非致命)", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 尝试解包 ResponseWrapper 标准格式 {code:0, message:"...", data:{...}}
|
||||
// 只在目标是 map[string]interface{} 时尝试透明解包
|
||||
if target, ok := v.(*map[string]interface{}); ok {
|
||||
var outer struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
if json.Unmarshal(raw, &outer) == nil && outer.Data != nil && len(outer.Data) > 2 {
|
||||
// 有 data 字段,尝试把 data 内容解包到目标
|
||||
var inner map[string]interface{}
|
||||
if json.Unmarshal(outer.Data, &inner) == nil && len(inner) > 0 {
|
||||
*target = inner
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 退化:直接解析原始 JSON
|
||||
if err := json.Unmarshal(raw, v); err != nil {
|
||||
t.Logf("解析响应 JSON 失败: %v(非致命)", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user