package auth import ( "encoding/hex" "fmt" "log" "net/http" "time" "sms-receiver-go/config" "github.com/gorilla/sessions" ) var store *sessions.CookieStore // SessionKey 会话相关的 key const ( SessionKeyLoggedIn = "logged_in" SessionKeyUsername = "username" SessionKeyLoginTime = "login_time" SessionKeyLastActive = "last_activity" ) // Init 初始化会话存储 func Init(secretKey string) error { if secretKey == "" { return fmt.Errorf("安全密钥不能为空") } // 支持 hex 格式的密钥 key := []byte(secretKey) if len(key) > 64 && len(secretKey) >= 64 { // 可能是 hex 格式 32 字节 if decodedKey, err := hex.DecodeString(secretKey); err == nil { key = decodedKey log.Printf("使用 hex 解码密钥") } else { log.Printf("hex 解码失败,使用原始密钥: %v", err) } } // 检查密钥长度(至少16字节) if len(key) < 16 { return fmt.Errorf("安全密钥长度不足,至少需要16字节(当前: %d 字节)", len(key)) } store = sessions.NewCookieStore(key) store.Options = &sessions.Options{ Path: "/", MaxAge: 86400 * 7, // 7天 HttpOnly: true, // 不设置 SameSite,让浏览器使用默认值(Lax),在同站上下文中工作正常 // SameSite: http.SameSiteNoneMode, // Secure: true, } log.Printf("会话存储初始化完成,密钥长度: %d 字节", len(key)) return nil } // GetStore 获取会话存储 func GetStore() *sessions.CookieStore { return store } // Login 登录 func Login(w http.ResponseWriter, r *http.Request, username string) error { session, err := store.Get(r, "sms-receiver") if err != nil { return err } session.Values[SessionKeyLoggedIn] = true session.Values[SessionKeyUsername] = username session.Values[SessionKeyLoginTime] = time.Now().Unix() session.Values[SessionKeyLastActive] = time.Now().Unix() return session.Save(r, w) } // Logout 登出 func Logout(r *http.Request, w http.ResponseWriter) error { session, err := store.Get(r, "sms-receiver") if err != nil { return err } session.Values = make(map[interface{}]interface{}) session.Save(r, w) return nil } // IsLoggedIn 检查是否已登录 func IsLoggedIn(r *http.Request) (bool, string) { session, err := store.Get(r, "sms-receiver") if err != nil { return false, "" } loggedIn, ok := session.Values[SessionKeyLoggedIn].(bool) if !ok || !loggedIn { return false, "" } username, _ := session.Values[SessionKeyUsername].(string) // 检查会话是否过期 cfg := config.Get() if cfg != nil { lastActive, ok := session.Values[SessionKeyLastActive].(int64) if ok { sessionLifetime := cfg.GetSessionLifetimeDuration() if time.Now().Unix()-lastActive > int64(sessionLifetime.Seconds()) { return false, "" } // 更新最后活跃时间 session.Values[SessionKeyLastActive] = time.Now().Unix() } } return true, username } // CheckLogin 检查登录状态,未登录则跳转到登录页 func CheckLogin(w http.ResponseWriter, r *http.Request) (bool, string) { loggedIn, username := IsLoggedIn(r) if !loggedIn { http.Redirect(w, r, "/login", http.StatusSeeOther) return false, "" } return true, username } // GetCurrentUser 获取当前用户名 func GetCurrentUser(r *http.Request) string { session, err := store.Get(r, "sms-receiver") if err != nil { return "" } username, _ := session.Values[SessionKeyUsername].(string) return username }