package middleware import ( "context" "github.com/gogf/gf/v2/net/ghttp" "service.xpcool.com/internal/consts" "service.xpcool.com/internal/library/jwt" "service.xpcool.com/internal/library/response" "strings" "time" ) type contextKey string const ( UserIDKey contextKey = "userId" AdminIDKey contextKey = "adminId" PermissionKey contextKey = "permission" ) func bearer(r *ghttp.Request) string { // 统一从 Authorization: Bearer 提取令牌。 return strings.TrimSpace(strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer")) } func auditParam(raw string) string { // 操作日志需要参数用于审计,但绝不记录密码、令牌和验证码等敏感字段。 lower := strings.ToLower(raw) if strings.Contains(lower, "password") || strings.Contains(lower, "token") || strings.Contains(lower, "code") { return "[redacted]" } return raw } func UserAuth(s *jwt.Service) ghttp.HandlerFunc { // 用户端仅接受 scope=user 的 access token。 return func(r *ghttp.Request) { c, err := s.Parse(bearer(r), "access", "user") if err != nil { response.JSON(r, consts.CodeUnauthorized, "login required", nil) return } r.SetCtxVar(UserIDKey, c.Subject) r.Middleware.Next() } } func AdminAuth(s *jwt.Service, permissionCheck func(context.Context, uint64, string) (bool, error), audit func(context.Context, uint64, string, string, string, string, string, int, int)) ghttp.HandlerFunc { // 管理端在令牌通过后继续校验 X-Permission 对应的 RBAC 权限,并在请求结束后记审计日志。 return func(r *ghttp.Request) { start := time.Now() c, err := s.Parse(bearer(r), "access", "admin") if err != nil { response.JSON(r, consts.CodeUnauthorized, "admin login required", nil) return } permission := r.Header.Get("X-Permission") if permission == "" { response.JSON(r, consts.CodeForbidden, "permission identifier required", nil) return } ok, err := permissionCheck(r.Context(), c.Subject, permission) if err != nil || !ok { response.JSON(r, consts.CodeAdminPermissionDenied, "permission denied", nil) return } defer func() { audit(r.Context(), c.Subject, permission, r.Method, r.URL.Path, r.GetClientIp(), auditParam(r.GetBodyString()), int(time.Since(start).Milliseconds()), r.Response.Status) }() r.SetCtxVar(AdminIDKey, c.Subject) r.SetCtxVar(PermissionKey, permission) r.Middleware.Next() } }