package handlers import ( "cs-bridge/internal/auth" "cs-bridge/pkg/logger" "encoding/json" "fmt" "net/http" "go.uber.org/zap" ) // ValidateTokenResponse Token验证响应结构 type ValidateTokenResponse struct { Success bool `json:"success"` Workspace string `json:"workspace,omitempty"` Error string `json:"error,omitempty"` } // ValidateWorkspaceToken Token验证处理器(供nginx调用) // nginx通过此接口验证token并获取workspace路径 func ValidateWorkspaceToken() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { log := logger.GetLogger() // 获取token参数 - 优先从query获取,否则从header获取(nginx auth_request场景) token := r.URL.Query().Get("token") if token == "" { token = r.Header.Get("X-Auth-Token") } log.Info("[Auth] 收到验证请求", zap.String("url", r.URL.String()), zap.Bool("has_token", token != "")) if token == "" { // 无token时返回200,允许请求通过(不设置X-Workspace) // 这样静态资源等请求可以正常访问 log.Debug("[Auth] 无token, 允许通过") w.WriteHeader(http.StatusOK) return } // 验证token (可多次使用,直到过期) log.Info(fmt.Sprintf("[Auth] 开始验证token: %s...", token[:min(16, len(token))])) workspacePath, err := auth.ValidateAndConsumeToken(token) if err != nil { log.Error(fmt.Sprintf("[Auth] Token验证失败: %v", err)) w.Header().Set("Content-Type", "application/json") // 根据错误类型返回不同的状态码 switch err { case auth.ErrTokenNotFound: w.WriteHeader(http.StatusNotFound) case auth.ErrTokenExpired: w.WriteHeader(http.StatusGone) default: w.WriteHeader(http.StatusInternalServerError) } json.NewEncoder(w).Encode(ValidateTokenResponse{ Success: false, Error: err.Error(), }) return } log.Info(fmt.Sprintf("[Auth] Token验证成功, Workspace: %s", workspacePath)) // 返回成功响应 w.Header().Set("X-Workspace", workspacePath) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(ValidateTokenResponse{ Success: true, Workspace: workspacePath, }) } } func min(a, b int) int { if a < b { return a } return b }