// Package auditcontext 提供跨 HTTP、异步任务和外部回调传播的审计上下文。 package auditcontext import "context" type contextKey struct{} // Context 保存入口提供的真实操作者与链路信息,不包含业务动作或资源事实。 type Context struct { ActorKind string ActorID string ActorName string ActorShopID *uint ActorEnterpriseID *uint Source string RequestID string CorrelationID string ParentEventID string RequestPath string RequestMethod string IPAddress string UserAgent string } // With 合并审计上下文;非空新值覆盖旧值,便于认证中间件覆盖 HTTP 基础信息。 func With(ctx context.Context, value Context) context.Context { if ctx == nil { ctx = context.Background() } merged := From(ctx) merge(&merged, value) return context.WithValue(ctx, contextKey{}, merged) } // From 读取审计上下文;未设置时返回零值。 func From(ctx context.Context) Context { if ctx == nil { return Context{} } value, _ := ctx.Value(contextKey{}).(Context) return value } func merge(target *Context, value Context) { if value.ActorKind != "" { target.ActorKind = value.ActorKind } if value.ActorID != "" { target.ActorID = value.ActorID } if value.ActorName != "" { target.ActorName = value.ActorName } if value.ActorShopID != nil { target.ActorShopID = value.ActorShopID } if value.ActorEnterpriseID != nil { target.ActorEnterpriseID = value.ActorEnterpriseID } if value.Source != "" { target.Source = value.Source } if value.RequestID != "" { target.RequestID = value.RequestID } if value.CorrelationID != "" { target.CorrelationID = value.CorrelationID } if value.ParentEventID != "" { target.ParentEventID = value.ParentEventID } if value.RequestPath != "" { target.RequestPath = value.RequestPath } if value.RequestMethod != "" { target.RequestMethod = value.RequestMethod } if value.IPAddress != "" { target.IPAddress = value.IPAddress } if value.UserAgent != "" { target.UserAgent = value.UserAgent } }