user.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. package user
  2. import (
  3. "crypto/rand"
  4. "encoding/base64"
  5. "time"
  6. "github.com/0xJacky/Nginx-UI/model"
  7. "github.com/0xJacky/Nginx-UI/query"
  8. "github.com/golang-jwt/jwt/v5"
  9. "github.com/spf13/cast"
  10. "github.com/uozi-tech/cosy/logger"
  11. cSettings "github.com/uozi-tech/cosy/settings"
  12. )
  13. const ExpiredTime = 24 * time.Hour
  14. type JWTClaims struct {
  15. Name string `json:"name"`
  16. UserID uint64 `json:"user_id"`
  17. jwt.RegisteredClaims
  18. }
  19. func GetUser(name string) (user *model.User, err error) {
  20. db := model.UseDB()
  21. user = &model.User{}
  22. err = db.Where("name", name).First(user).Error
  23. if err != nil {
  24. return
  25. }
  26. return
  27. }
  28. func DeleteToken(token string) {
  29. // Remove from cache first
  30. InvalidateTokenCache(token)
  31. // Remove from database
  32. q := query.AuthToken
  33. _, _ = q.Where(q.Token.Eq(token)).Delete()
  34. }
  35. func GetTokenUser(token string) (*model.User, bool) {
  36. _, err := ValidateJWT(token)
  37. if err != nil {
  38. logger.Error(err)
  39. return nil, false
  40. }
  41. // Try to get from cache first
  42. if tokenData, found := GetCachedTokenData(token); found {
  43. // Get user from cache or database
  44. if user, userFound := GetCachedUser(tokenData.UserID); userFound {
  45. return user, true
  46. }
  47. // User not in cache, load from database and cache it
  48. u := query.User
  49. user, err := u.FirstByID(tokenData.UserID)
  50. if err == nil {
  51. CacheUser(user)
  52. return user, true
  53. }
  54. return nil, false
  55. }
  56. // Not in cache, load from database
  57. q := query.AuthToken
  58. authToken, err := q.Where(q.Token.Eq(token)).First()
  59. if err != nil {
  60. return nil, false
  61. }
  62. if authToken.ExpiredAt < time.Now().Unix() {
  63. DeleteToken(token)
  64. return nil, false
  65. }
  66. // Cache the token data
  67. CacheToken(authToken)
  68. // Get user and cache it
  69. u := query.User
  70. user, err := u.FirstByID(authToken.UserID)
  71. if err == nil {
  72. CacheUser(user)
  73. return user, true
  74. }
  75. return user, err == nil
  76. }
  77. func GetTokenUserByShortToken(shortToken string) (*model.User, bool) {
  78. if shortToken == "" {
  79. return nil, false
  80. }
  81. // Try to get from cache first
  82. if tokenData, found := GetCachedShortTokenData(shortToken); found {
  83. // Get user from cache or database
  84. if user, userFound := GetCachedUser(tokenData.UserID); userFound {
  85. return user, true
  86. }
  87. // User not in cache, load from database and cache it
  88. u := query.User
  89. user, err := u.FirstByID(tokenData.UserID)
  90. if err == nil {
  91. CacheUser(user)
  92. return user, true
  93. }
  94. return nil, false
  95. }
  96. // Not in cache, load from database
  97. db := model.UseDB()
  98. var authToken model.AuthToken
  99. err := db.Where("short_token = ?", shortToken).First(&authToken).Error
  100. if err != nil {
  101. return nil, false
  102. }
  103. if authToken.ExpiredAt < time.Now().Unix() {
  104. DeleteToken(authToken.Token)
  105. return nil, false
  106. }
  107. // Cache the token data
  108. CacheToken(&authToken)
  109. // Get user and cache it
  110. u := query.User
  111. user, err := u.FirstByID(authToken.UserID)
  112. if err == nil {
  113. CacheUser(user)
  114. return user, true
  115. }
  116. return user, err == nil
  117. }
  118. type AccessTokenPayload struct {
  119. Token string `json:"token,omitempty"`
  120. ShortToken string `json:"short_token,omitempty"`
  121. }
  122. func GenerateJWT(user *model.User) (*AccessTokenPayload, error) {
  123. now := time.Now()
  124. claims := JWTClaims{
  125. Name: user.Name,
  126. UserID: user.ID,
  127. RegisteredClaims: jwt.RegisteredClaims{
  128. ExpiresAt: jwt.NewNumericDate(now.Add(ExpiredTime)),
  129. IssuedAt: jwt.NewNumericDate(now),
  130. NotBefore: jwt.NewNumericDate(now),
  131. Issuer: "Nginx UI",
  132. Subject: user.Name,
  133. ID: cast.ToString(user.ID),
  134. },
  135. }
  136. unsignedToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  137. signedToken, err := unsignedToken.SignedString([]byte(cSettings.AppSettings.JwtSecret))
  138. if err != nil {
  139. return nil, err
  140. }
  141. // Generate 16-byte short token (16 characters)
  142. shortTokenBytes := make([]byte, 16)
  143. _, err = rand.Read(shortTokenBytes)
  144. if err != nil {
  145. return nil, err
  146. }
  147. // Use base64 URL encoding to get a 16-character string
  148. shortToken := base64.URLEncoding.EncodeToString(shortTokenBytes)[:16]
  149. authToken := &model.AuthToken{
  150. UserID: user.ID,
  151. Token: signedToken,
  152. ShortToken: shortToken,
  153. ExpiredAt: now.Add(ExpiredTime).Unix(),
  154. }
  155. q := query.AuthToken
  156. err = q.Create(authToken)
  157. if err != nil {
  158. return nil, err
  159. }
  160. // Cache the new token
  161. CacheToken(authToken)
  162. return &AccessTokenPayload{
  163. Token: signedToken,
  164. ShortToken: shortToken,
  165. }, nil
  166. }
  167. func ValidateJWT(tokenStr string) (claims *JWTClaims, err error) {
  168. if tokenStr == "" {
  169. err = ErrTokenIsEmpty
  170. return
  171. }
  172. token, err := jwt.ParseWithClaims(tokenStr, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
  173. return []byte(cSettings.AppSettings.JwtSecret), nil
  174. })
  175. if err != nil {
  176. return
  177. }
  178. var ok bool
  179. if claims, ok = token.Claims.(*JWTClaims); ok && token.Valid {
  180. return claims, nil
  181. }
  182. return nil, ErrInvalidClaimsType
  183. }