Cookie与Session #

一、Cookie基础 #

1.1 什么是Cookie #

Cookie是存储在客户端的小型数据,用于在HTTP请求之间保持状态。

1.2 Cookie属性 #

属性 说明
Name Cookie名称
Value Cookie值
Path 有效路径
Domain 有效域名
Expires 过期时间
MaxAge 最大存活时间(秒)
Secure 仅HTTPS传输
HTTPOnly 禁止JavaScript访问
SameSite 跨站策略

二、Cookie操作 #

2.1 获取Cookie #

go
app.Get("/get-cookie", func(c *fiber.Ctx) error {
    // 获取单个Cookie
    session := c.Cookies("session")
    token := c.Cookies("token", "default")
    
    return c.JSON(fiber.Map{
        "session": session,
        "token":   token,
    })
})

2.2 设置Cookie #

go
app.Get("/set-cookie", func(c *fiber.Ctx) error {
    c.Cookie(&fiber.Cookie{
        Name:     "session",
        Value:    "abc123",
        Expires:  time.Now().Add(24 * time.Hour),
        HTTPOnly: true,
        Secure:   true,
        SameSite: "Lax",
    })
    
    return c.SendString("Cookie set")
})

2.3 Cookie完整配置 #

go
app.Get("/full-cookie", func(c *fiber.Ctx) error {
    c.Cookie(&fiber.Cookie{
        Name:        "user",
        Value:       "john",
        Path:        "/",
        Domain:      "example.com",
        Expires:     time.Now().Add(24 * time.Hour),
        MaxAge:      86400,
        Secure:      true,
        HTTPOnly:    true,
        SameSite:    "Strict",
        SessionOnly: false,
    })
    
    return c.SendString("Full cookie set")
})

2.4 删除Cookie #

go
app.Get("/clear-cookie", func(c *fiber.Ctx) error {
    c.ClearCookie("session")
    return c.SendString("Cookie cleared")
})

// 删除多个Cookie
app.Get("/clear-cookies", func(c *fiber.Ctx) error {
    c.ClearCookie("session", "token", "user")
    return c.SendString("Cookies cleared")
})

2.5 Cookie安全配置 #

go
func SetSecureCookie(c *fiber.Ctx, name, value string, maxAge int) {
    c.Cookie(&fiber.Cookie{
        Name:     name,
        Value:    value,
        MaxAge:   maxAge,
        Secure:   true,      // 仅HTTPS
        HTTPOnly: true,      // 禁止JS访问
        SameSite: "Strict",  // 严格同源
        Path:     "/",
    })
}

app.Get("/secure-cookie", func(c *fiber.Ctx) error {
    SetSecureCookie(c, "auth_token", "xyz789", 3600)
    return c.SendString("Secure cookie set")
})

三、Session管理 #

3.1 什么是Session #

Session是存储在服务器端的会话数据,通过Session ID与客户端关联。

3.2 内存Session #

go
package main

import (
    "sync"
    
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/middleware/session"
)

var store = session.New()

func main() {
    app := fiber.New()
    
    app.Get("/login", func(c *fiber.Ctx) error {
        // 获取Session
        sess, err := store.Get(c)
        if err != nil {
            return err
        }
        
        // 设置Session数据
        sess.Set("user_id", 123)
        sess.Set("username", "john")
        
        // 保存Session
        if err := sess.Save(); err != nil {
            return err
        }
        
        return c.SendString("Logged in")
    })
    
    app.Get("/profile", func(c *fiber.Ctx) error {
        sess, err := store.Get(c)
        if err != nil {
            return err
        }
        
        userID := sess.Get("user_id")
        username := sess.Get("username")
        
        if userID == nil {
            return c.Status(401).SendString("Not logged in")
        }
        
        return c.JSON(fiber.Map{
            "user_id":  userID,
            "username": username,
        })
    })
    
    app.Get("/logout", func(c *fiber.Ctx) error {
        sess, err := store.Get(c)
        if err != nil {
            return err
        }
        
        // 销毁Session
        if err := sess.Destroy(); err != nil {
            return err
        }
        
        return c.SendString("Logged out")
    })
    
    app.Listen(":3000")
}

3.3 Session配置 #

go
var store = session.New(session.Config{
    // Session过期时间
    Expiration: 24 * time.Hour,
    
    // Cookie名称
    KeyLookup: "cookie:session_id",
    
    // Cookie配置
    Cookie: fiber.Cookie{
        Secure:   true,
        HTTPOnly: true,
        SameSite: "Lax",
    },
    
    // Key生成器
    KeyGenerator: func() string {
        return uuid.New().String()
    },
})

3.4 Redis Session存储 #

go
package main

import (
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/middleware/session"
    "github.com/gofiber/storage/redis"
)

func main() {
    // Redis存储
    storage := redis.New(redis.Config{
        Host:     "localhost",
        Port:     6379,
        Password: "",
        Database: 0,
    })
    
    // Session存储
    store := session.New(session.Config{
        Storage:    storage,
        Expiration: 24 * time.Hour,
    })
    
    app := fiber.New()
    
    app.Get("/login", func(c *fiber.Ctx) error {
        sess, err := store.Get(c)
        if err != nil {
            return err
        }
        
        sess.Set("user_id", 123)
        sess.Save()
        
        return c.SendString("Logged in")
    })
    
    app.Listen(":3000")
}

四、Session中间件 #

4.1 认证中间件 #

go
func AuthRequired(store *session.Store) fiber.Handler {
    return func(c *fiber.Ctx) error {
        sess, err := store.Get(c)
        if err != nil {
            return c.Status(500).SendString("Session error")
        }
        
        userID := sess.Get("user_id")
        if userID == nil {
            return c.Status(401).JSON(fiber.Map{
                "error": "Unauthorized",
            })
        }
        
        c.Locals("user_id", userID)
        return c.Next()
    }
}

// 使用
app.Get("/protected", AuthRequired(store), func(c *fiber.Ctx) error {
    userID := c.Locals("user_id")
    return c.JSON(fiber.Map{"user_id": userID})
})

4.2 完整认证示例 #

go
package main

import (
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/middleware/session"
)

var store = session.New()

func main() {
    app := fiber.New()
    
    // 登录
    app.Post("/login", func(c *fiber.Ctx) error {
        type LoginInput struct {
            Username string `json:"username"`
            Password string `json:"password"`
        }
        
        var input LoginInput
        if err := c.BodyParser(&input); err != nil {
            return c.Status(400).JSON(fiber.Map{
                "error": "Invalid input",
            })
        }
        
        // 验证用户(示例)
        if input.Username != "admin" || input.Password != "password" {
            return c.Status(401).JSON(fiber.Map{
                "error": "Invalid credentials",
            })
        }
        
        // 创建Session
        sess, err := store.Get(c)
        if err != nil {
            return err
        }
        
        sess.Set("user_id", 1)
        sess.Set("username", input.Username)
        sess.Save()
        
        return c.JSON(fiber.Map{
            "message": "Login successful",
        })
    })
    
    // 获取用户信息
    app.Get("/me", AuthRequired(store), func(c *fiber.Ctx) error {
        sess, _ := store.Get(c)
        
        return c.JSON(fiber.Map{
            "user_id":  sess.Get("user_id"),
            "username": sess.Get("username"),
        })
    })
    
    // 登出
    app.Post("/logout", func(c *fiber.Ctx) error {
        sess, err := store.Get(c)
        if err != nil {
            return err
        }
        
        sess.Destroy()
        
        return c.JSON(fiber.Map{
            "message": "Logout successful",
        })
    })
    
    app.Listen(":3000")
}

五、Session数据操作 #

5.1 设置数据 #

go
sess.Set("key", "value")
sess.Set("user", fiber.Map{
    "id":   1,
    "name": "John",
})

5.2 获取数据 #

go
value := sess.Get("key")

// 类型断言
if user, ok := sess.Get("user").(fiber.Map); ok {
    fmt.Println(user["name"])
}

5.3 删除数据 #

go
sess.Delete("key")

5.4 检查数据 #

go
if sess.Get("user_id") != nil {
    // 已登录
}

5.5 获取Session ID #

go
sess, _ := store.Get(c)
sessionID := sess.ID()

5.6 重新生成Session ID #

go
sess.Regenerate()

六、安全最佳实践 #

6.1 Cookie安全配置 #

go
c.Cookie(&fiber.Cookie{
    Name:     "session",
    Value:    sessionID,
    Secure:   true,      // 仅HTTPS
    HTTPOnly: true,      // 防止XSS
    SameSite: "Strict",  // 防止CSRF
    MaxAge:   3600,      // 限制有效期
    Path:     "/",
})

6.2 Session安全配置 #

go
var store = session.New(session.Config{
    Expiration: 30 * time.Minute,
    KeyLookup:  "cookie:session_id",
    Cookie: fiber.Cookie{
        Secure:   true,
        HTTPOnly: true,
        SameSite: "Strict",
    },
})

6.3 防止Session劫持 #

go
func SecureSession(c *fiber.Ctx, sess *session.Session) {
    // 绑定IP
    sess.Set("ip", c.IP())
    
    // 绑定User-Agent
    sess.Set("user_agent", c.Get("User-Agent"))
}

func ValidateSession(c *fiber.Ctx, sess *session.Session) bool {
    storedIP := sess.Get("ip")
    storedUA := sess.Get("user_agent")
    
    if storedIP != nil && storedIP != c.IP() {
        return false
    }
    
    if storedUA != nil && storedUA != c.Get("User-Agent") {
        return false
    }
    
    return true
}

七、总结 #

7.1 Cookie与Session对比 #

特性 Cookie Session
存储位置 客户端 服务器
安全性 较低 较高
大小限制 4KB 无限制
性能 需要存储开销

7.2 下一步 #

现在你已经了解了Cookie与Session,接下来让我们学习 文件上传下载,了解文件处理!

最后更新:2026-03-28