refactor(go)!: 分离练习区与独立项目区
- 将现有练习及 module 文件迁移至 go/practice,保持代码和依赖不变 - 新增 go/projects 项目区说明,更新目录约定与开发命令 BREAKING CHANGE: Go 练习命令需改在 go/practice 目录下执行
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-contrib/sessions/cookie"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var (
|
||||
mockUsers = map[string]string{
|
||||
"zhangsan": "123456",
|
||||
"lisi": "654321",
|
||||
}
|
||||
// secretKey = "your-secret-key"
|
||||
hmacSecretKey = "5KiinhGcvoXFmgOttvgMWd9ugadE0KVP"
|
||||
blockSecretKey = "OLZmfTWHGyjCfJoH1Y8SjbSY"
|
||||
)
|
||||
|
||||
const sessionTTL = 60 * 5
|
||||
|
||||
func sessionOptions(maxAge int) sessions.Options {
|
||||
return sessions.Options{
|
||||
Path: "/",
|
||||
Domain: "", // 设置为 "" 表示当前域名
|
||||
MaxAge: maxAge, // 单位为秒。0 表示不写Max-Age(浏览器会话cookie); -1 表示删除 cookie
|
||||
Secure: false, // 生产走 HTTPS 时改 true
|
||||
HttpOnly: true, // true 表示禁止 JS 读取 cookie
|
||||
SameSite: http.SameSiteStrictMode, // 严格模式,仅在同源请求中发送 cookie
|
||||
}
|
||||
}
|
||||
|
||||
// 代码来自文章 https://www.cnblogs.com/XY-Heruo/p/22864951
|
||||
func main() {
|
||||
r := gin.Default()
|
||||
|
||||
// Create cookie-based session store with a secret key
|
||||
// 传单个密钥时, 只做签名认证,不加密cookie内容. 认证密钥建议 32 或 64 字节
|
||||
// 传一对密钥时,第一个用于认证(HMAC),第二个用于加密(AES-128, AES-192, AES-256)。加密密钥必须是16、24或32字节长度,对应 AES-128/192/256。
|
||||
// 多对密钥用于密钥轮换,第一对用于当前加密和认证,后续的用于解密和认证旧的cookie。Example: cookie.NewStore([]byte("newAuth"), []byte("newEnc"), []byte("oldAuth"), []byte("oldEnc"))
|
||||
store := cookie.NewStore([]byte(hmacSecretKey), []byte(blockSecretKey))
|
||||
store.Options(sessionOptions(sessionTTL)) // 全局设置 cookie 过期时间为 5 分钟
|
||||
r.Use(sessions.Sessions("mysession", store))
|
||||
|
||||
r.POST("/login", login)
|
||||
|
||||
auth := r.Group("/", authRequired())
|
||||
|
||||
auth.GET("/profile", profile)
|
||||
auth.POST("/logout", logout)
|
||||
|
||||
r.Run(":8080")
|
||||
}
|
||||
|
||||
func login(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
username := c.PostForm("username")
|
||||
password := c.PostForm("password")
|
||||
|
||||
if username == "" || password == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "username or password is empty"})
|
||||
return
|
||||
}
|
||||
|
||||
if mockUsers[username] != password {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid username or password"})
|
||||
return
|
||||
}
|
||||
|
||||
session.Set("user", username)
|
||||
session.Set("expire_at", time.Now().Add(time.Second*sessionTTL).Unix()) // 设置过期时间
|
||||
if err := session.Save(); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "save session failed"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "logged in"})
|
||||
}
|
||||
|
||||
func logout(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
session.Clear()
|
||||
session.Options(sessionOptions(-1)) // 让浏览器删除 cookie
|
||||
if err := session.Save(); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "save session failed"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"message": "logged out"})
|
||||
}
|
||||
|
||||
func profile(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
user := session.Get("user").(string)
|
||||
c.JSON(http.StatusOK, gin.H{"user": user})
|
||||
}
|
||||
|
||||
func authRequired() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
if session.Get("user") == nil {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
|
||||
return
|
||||
}
|
||||
|
||||
if expireAt, ok := session.Get("expire_at").(int64); !ok || time.Now().Unix() > expireAt {
|
||||
session.Clear()
|
||||
session.Options(sessionOptions(-1))
|
||||
session.Save()
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "expired session"})
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user