package utils import ( "crypto/hmac" "crypto/sha256" "encoding/base64" "encoding/json" "fmt" "net/url" "os" "path/filepath" "strings" "time" "github.com/gin-gonic/gin" ) var adminSecret string // InitAuth 设置后台 token 签名密钥 func InitAuth(secret string) { adminSecret = secret } func GetEnv(k, def string) string { if v := os.Getenv(k); v != "" { return v } return def } func SignToken(account string) string { payload := fmt.Sprintf(`{"account":%q,"exp":%d}`, account, time.Now().Add(24*time.Hour).Unix()) b64 := base64.StdEncoding.EncodeToString([]byte(payload)) mac := hmac.New(sha256.New, []byte(adminSecret)) mac.Write([]byte(b64)) sig := base64.StdEncoding.EncodeToString(mac.Sum(nil)) return b64 + "." + sig } func SignCashGiftViewToken() string { payload := fmt.Sprintf(`{"account":%q,"exp":%d}`, "cash-gift-view", time.Now().Add(7*24*time.Hour).Unix()) b64 := base64.StdEncoding.EncodeToString([]byte(payload)) mac := hmac.New(sha256.New, []byte(adminSecret)) mac.Write([]byte(b64)) sig := base64.StdEncoding.EncodeToString(mac.Sum(nil)) return b64 + "." + sig } func SignCashGiftEntryToken() string { payload := fmt.Sprintf(`{"account":%q,"exp":%d}`, "cash-gift-entry", time.Now().Add(7*24*time.Hour).Unix()) b64 := base64.StdEncoding.EncodeToString([]byte(payload)) mac := hmac.New(sha256.New, []byte(adminSecret)) mac.Write([]byte(b64)) sig := base64.StdEncoding.EncodeToString(mac.Sum(nil)) return b64 + "." + sig } func parseTokenClaims(token string) (account string, exp int64, ok bool) { parts := strings.Split(token, ".") if len(parts) != 2 { return "", 0, false } mac := hmac.New(sha256.New, []byte(adminSecret)) mac.Write([]byte(parts[0])) expected := base64.StdEncoding.EncodeToString(mac.Sum(nil)) if !hmac.Equal([]byte(expected), []byte(parts[1])) { return "", 0, false } raw, err := base64.StdEncoding.DecodeString(parts[0]) if err != nil { return "", 0, false } var claims struct { Account string `json:"account"` Exp int64 `json:"exp"` } if err := json.Unmarshal(raw, &claims); err != nil { return "", 0, false } if time.Now().Unix() > claims.Exp { return "", 0, false } return claims.Account, claims.Exp, true } func VerifyToken(token string) bool { _, _, ok := parseTokenClaims(token) return ok } func VerifyCashGiftViewToken(token string) bool { account, _, ok := parseTokenClaims(token) return ok && account == "cash-gift-view" } func VerifyCashGiftEntryToken(token string) bool { account, _, ok := parseTokenClaims(token) return ok && account == "cash-gift-entry" } func BearerToken(c *gin.Context) string { return strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ") } func RequireAdmin(c *gin.Context) bool { if !VerifyToken(BearerToken(c)) { c.JSON(401, gin.H{"error": "未授权,请先登录后台"}) return false } return true } func CORSMiddleware() gin.HandlerFunc { return func(c *gin.Context) { c.Writer.Header().Set("Access-Control-Allow-Origin", "*") c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT") c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Cash-Gift-Token, X-Cash-Gift-Entry-Token") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.Next() } } func EscapeMySQLComment(s string) string { s = strings.ReplaceAll(s, `\`, `\\`) s = strings.ReplaceAll(s, `'`, `''`) return s } func CleanObjectName(name string) string { name = filepath.Base(name) name = strings.ReplaceAll(name, "\\", "_") name = strings.ReplaceAll(name, "/", "_") name = strings.TrimSpace(name) if name == "" || name == "." { return "upload" } return name } func BuildObjectKey(folder string, originalName string) string { folder = strings.Trim(folder, "/ ") name := CleanObjectName(originalName) fileName := fmt.Sprintf("%s_%s", time.Now().Format("150405000000000"), name) day := time.Now().Format("20060102") if folder == "" { return day + "/" + fileName } return folder + "/" + day + "/" + fileName } func EscapedObjectKey(key string) string { parts := strings.Split(key, "/") for i, part := range parts { parts[i] = url.PathEscape(part) } return strings.Join(parts, "/") } func NormalizeEndpoint(endpoint string, region string) string { endpoint = strings.TrimSpace(endpoint) region = strings.TrimSpace(region) if endpoint == "" && region != "" { endpoint = "https://oss-" + region + ".aliyuncs.com" } if endpoint != "" && !strings.HasPrefix(endpoint, "http://") && !strings.HasPrefix(endpoint, "https://") { endpoint = "https://" + endpoint } return endpoint }