diff --git a/middleware/auth.go b/middleware/auth.go index 1a70f54..2e41910 100644 --- a/middleware/auth.go +++ b/middleware/auth.go @@ -30,6 +30,32 @@ func validUserInfo(username string, role int) bool { return true } +// parseTokenKey 解析令牌字符串,提取 key 和可选的 channelId +// 支持格式:sk-{key} 或 sk-{key}:{channelId} 或 sk-{key}-{channelId} +// 返回:key, parts(parts[0]=key, parts[1]=channelId 如果指定) +func parseTokenKey(key string) (string, []string) { + key = strings.TrimPrefix(key, "sk-") + + // 先按冒号分割获取 channelId(新格式:sk-{key}:{channelId}) + var colonChannelId string + if colonIdx := strings.Index(key, ":"); colonIdx != -1 { + colonChannelId = key[colonIdx+1:] + key = key[:colonIdx] + } + + parts := strings.Split(key, "-") + key = parts[0] + + // 如果冒号方式指定了渠道,验证并追加到 parts + if colonChannelId != "" { + // 验证 channelId 为有效数字,防止 sk-abc:def:ghi 等格式 + if _, err := strconv.Atoi(colonChannelId); err == nil { + parts = append(parts, colonChannelId) + } + } + return key, parts +} + func authHelper(c *gin.Context, minRole int) { session := sessions.Default(c) username := session.Get("username") @@ -293,34 +319,8 @@ func TokenAuth() func(c *gin.Context) { if strings.HasPrefix(key, "Bearer ") || strings.HasPrefix(key, "bearer ") { key = strings.TrimSpace(key[7:]) } - key = strings.TrimPrefix(key, "sk-") - // 先按冒号分割获取 channelId(新格式:sk-{key}:{channelId}) - var colonChannelId string - if colonIdx := strings.Index(key, ":"); colonIdx != -1 { - colonChannelId = key[colonIdx+1:] - key = key[:colonIdx] - } - parts = strings.Split(key, "-") - key = parts[0] - // 如果冒号方式指定了渠道,追加到 parts - if colonChannelId != "" { - parts = append(parts, colonChannelId) - } - } else { - key = strings.TrimPrefix(key, "sk-") - // 先按冒号分割获取 channelId(新格式:sk-{key}:{channelId}) - var colonChannelId string - if colonIdx := strings.Index(key, ":"); colonIdx != -1 { - colonChannelId = key[colonIdx+1:] - key = key[:colonIdx] - } - parts = strings.Split(key, "-") - key = parts[0] - // 如果冒号方式指定了渠道,追加到 parts - if colonChannelId != "" { - parts = append(parts, colonChannelId) - } } + key, parts = parseTokenKey(key) token, err := model.ValidateUserToken(key) if token != nil { id := c.GetInt("id") diff --git a/model/main.go b/model/main.go index c06771a..d72e201 100644 --- a/model/main.go +++ b/model/main.go @@ -250,6 +250,8 @@ func InitLogDB() (err error) { func migrateDB() error { // Migrate price_amount column from float/double to decimal for existing tables migrateSubscriptionPlanPriceAmount() + // Drop bound_channel_id column from tokens table (deprecated field) + migrateTokenDropBoundChannelId() err := DB.AutoMigrate( &Channel{}, @@ -295,6 +297,8 @@ func migrateDB() error { } func migrateDBFast() error { + // Drop bound_channel_id column from tokens table (deprecated field) + migrateTokenDropBoundChannelId() var wg sync.WaitGroup @@ -506,6 +510,35 @@ func migrateSubscriptionPlanPriceAmount() { } } +// migrateTokenDropBoundChannelId 删除 tokens 表中的 bound_channel_id 列(已废弃的字段) +func migrateTokenDropBoundChannelId() { + // SQLite 不支持 DROP COLUMN,跳过迁移 + if common.UsingSQLite { + return + } + + tableName := "tokens" + columnName := "bound_channel_id" + + // 检查表是否存在 + if !DB.Migrator().HasTable(tableName) { + return + } + + // 检查列是否存在 + if !DB.Migrator().HasColumn(&Token{}, columnName) { + return + } + + // MySQL 和 PostgreSQL 都支持此语法 + dropSQL := fmt.Sprintf("ALTER TABLE %s DROP COLUMN %s", tableName, columnName) + if err := DB.Exec(dropSQL).Error; err != nil { + common.SysLog(fmt.Sprintf("Warning: failed to drop %s.%s: %v", tableName, columnName, err)) + } else { + common.SysLog(fmt.Sprintf("Successfully dropped deprecated column %s.%s", tableName, columnName)) + } +} + func closeDB(db *gorm.DB) error { sqlDB, err := db.DB() if err != nil {