1
0

session.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // Package session provides session management utilities for the 3x-ui web panel.
  2. // It handles user authentication state, login sessions, and session storage using Gin sessions.
  3. package session
  4. import (
  5. "encoding/gob"
  6. "net/http"
  7. "github.com/mhsanaei/3x-ui/v2/database/model"
  8. "github.com/mhsanaei/3x-ui/v2/logger"
  9. "github.com/gin-contrib/sessions"
  10. "github.com/gin-gonic/gin"
  11. )
  12. const (
  13. loginUserKey = "LOGIN_USER"
  14. )
  15. func init() {
  16. gob.Register(model.User{})
  17. }
  18. // SetLoginUser stores the authenticated user in the session and persists it.
  19. // gin-contrib/sessions does not auto-save; callers that forget Save() leave
  20. // the cookie out of sync with server state — this helper avoids that pitfall.
  21. func SetLoginUser(c *gin.Context, user *model.User) error {
  22. if user == nil {
  23. return nil
  24. }
  25. s := sessions.Default(c)
  26. s.Set(loginUserKey, *user)
  27. return s.Save()
  28. }
  29. // GetLoginUser retrieves the authenticated user from the session.
  30. // Returns nil if no user is logged in or if the session data is invalid.
  31. func GetLoginUser(c *gin.Context) *model.User {
  32. s := sessions.Default(c)
  33. obj := s.Get(loginUserKey)
  34. if obj == nil {
  35. return nil
  36. }
  37. user, ok := obj.(model.User)
  38. if !ok {
  39. // Stale or incompatible session payload — wipe and persist immediately
  40. // so subsequent requests don't keep hitting the same broken cookie.
  41. s.Delete(loginUserKey)
  42. if err := s.Save(); err != nil {
  43. logger.Warning("session: failed to drop stale user payload:", err)
  44. }
  45. return nil
  46. }
  47. return &user
  48. }
  49. // IsLogin checks if a user is currently authenticated in the session.
  50. func IsLogin(c *gin.Context) bool {
  51. return GetLoginUser(c) != nil
  52. }
  53. // ClearSession invalidates the session and tells the browser to drop the cookie.
  54. // The cookie attributes (Path/HttpOnly/SameSite) must mirror those used when
  55. // the cookie was created or browsers will keep it.
  56. func ClearSession(c *gin.Context) error {
  57. s := sessions.Default(c)
  58. s.Clear()
  59. cookiePath := c.GetString("base_path")
  60. if cookiePath == "" {
  61. cookiePath = "/"
  62. }
  63. s.Options(sessions.Options{
  64. Path: cookiePath,
  65. MaxAge: -1,
  66. HttpOnly: true,
  67. SameSite: http.SameSiteLaxMode,
  68. })
  69. return s.Save()
  70. }