package utils import ( "bytes" "encoding/json" "fmt" "io" "net/http" "time" "github.com/beego/beego/v2/server/web" ) // TokenUserInfo 从token验证API返回的用户信息 type TokenUserInfo struct { AccountID string `json:"accountID"` ID int64 `json:"id"` Name string `json:"name"` UserCode string `json:"userCode"` ContactNumber string `json:"contactNumber"` TokenType string `json:"token_type"` Exp int64 `json:"exp"` Iat int64 `json:"iat"` } // VerifyToken 验证token并返回用户信息 func VerifyToken(token string) (*TokenUserInfo, error) { if token == "" { return nil, fmt.Errorf("token不能为空") } // 从配置文件读取token验证API URL authAPIURL, err := web.AppConfig.String("auth_api_url") if err != nil || authAPIURL == "" { // 如果配置不存在,使用默认值 authAPIURL = "https://aqai.shudaodsj.com:22000/api/auth/verify" } fmt.Printf("🔐 开始验证Token...\n") fmt.Printf(" 验证API: %s\n", authAPIURL) // 构建请求体 requestBody := map[string]string{ "token": token, } jsonData, err := json.Marshal(requestBody) if err != nil { return nil, fmt.Errorf("序列化请求体失败: %v", err) } // 创建HTTP请求 req, err := http.NewRequest("POST", authAPIURL, bytes.NewBuffer(jsonData)) if err != nil { return nil, fmt.Errorf("创建请求失败: %v", err) } req.Header.Set("Content-Type", "application/json") // 重要:认证API需要在请求头中也携带 Authorization req.Header.Set("Authorization", "Bearer "+token) fmt.Printf(" 请求头 Authorization: Bearer %s...\n", token[:20]) // 发送请求 client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { fmt.Printf("❌ 请求token验证API失败: %v\n", err) return nil, fmt.Errorf("请求token验证API失败: %v", err) } defer resp.Body.Close() // 读取响应体 body, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("❌ 读取响应失败: %v\n", err) return nil, fmt.Errorf("读取响应失败: %v", err) } fmt.Printf(" 响应状态码: %d\n", resp.StatusCode) fmt.Printf(" 响应内容: %s\n", string(body)) // 检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("token验证失败,状态码: %d, 响应: %s", resp.StatusCode, string(body)) } // 解析响应 var userInfo TokenUserInfo if err := json.Unmarshal(body, &userInfo); err != nil { fmt.Printf("❌ 解析响应失败: %v\n", err) return nil, fmt.Errorf("解析token验证响应失败: %v", err) } // 检查token是否过期 if userInfo.Exp > 0 && time.Now().Unix() > userInfo.Exp { fmt.Printf("❌ Token已过期 (exp: %d, now: %d)\n", userInfo.Exp, time.Now().Unix()) return nil, fmt.Errorf("token已过期") } fmt.Printf("✅ Token验证成功\n") return &userInfo, nil } // GetUserInfoFromToken 从请求头中获取token并验证,返回用户信息 func GetUserInfoFromToken(headerFunc func(string) string) (*TokenUserInfo, error) { // 尝试从多个可能的header字段获取token token := headerFunc("token") fmt.Print("token", token) if token == "" { token = headerFunc("Token") } if token == "" { token = headerFunc("Authorization") // 如果是Bearer token格式,去掉"Bearer "前缀 if len(token) > 7 && token[:7] == "Bearer " { token = token[7:] } } if token == "" { return nil, fmt.Errorf("请求头中未找到token") } return VerifyToken(token) } // GetUserInfoFromContext 从Beego Context中获取已验证的用户信息 // 该函数假定中间件已经验证过token并将用户信息存储在context中 func GetUserInfoFromContext(input interface{}) (*TokenUserInfo, error) { // 添加调试信息 fmt.Printf("\n🔍 [GetUserInfoFromContext] 开始解析用户信息\n") fmt.Printf(" 输入类型: %T\n", input) fmt.Printf(" 输入值: %+v\n", input) // 检查input是否为nil if input == nil { fmt.Printf("❌ [GetUserInfoFromContext] input为nil\n\n") return nil, fmt.Errorf("未找到用户信息,context中userInfo为nil,请确保已经过token认证") } // 从context中获取userInfo userInfo, ok := input.(*TokenUserInfo) if !ok { fmt.Printf("❌ [GetUserInfoFromContext] 类型断言失败,期望 *TokenUserInfo,实际得到 %T\n\n", input) return nil, fmt.Errorf("用户信息类型错误,期望 *TokenUserInfo,实际得到 %T", input) } if userInfo == nil { fmt.Printf("❌ [GetUserInfoFromContext] userInfo为nil\n\n") return nil, fmt.Errorf("用户信息为空") } fmt.Printf("✅ [GetUserInfoFromContext] 成功解析用户信息\n") fmt.Printf(" - AccountID: %s\n", userInfo.AccountID) fmt.Printf(" - ID: %d\n", userInfo.ID) fmt.Printf(" - Name: %s\n\n", userInfo.Name) return userInfo, nil }