user.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. q := query.AuthToken
  30. _, _ = q.Where(q.Token.Eq(token)).Delete()
  31. }
  32. func GetTokenUser(token string) (*model.User, bool) {
  33. _, err := ValidateJWT(token)
  34. if err != nil {
  35. logger.Error(err)
  36. return nil, false
  37. }
  38. q := query.AuthToken
  39. authToken, err := q.Where(q.Token.Eq(token)).First()
  40. if err != nil {
  41. return nil, false
  42. }
  43. if authToken.ExpiredAt < time.Now().Unix() {
  44. DeleteToken(token)
  45. return nil, false
  46. }
  47. u := query.User
  48. user, err := u.FirstByID(authToken.UserID)
  49. return user, err == nil
  50. }
  51. func GetTokenUserByShortToken(shortToken string) (*model.User, bool) {
  52. if shortToken == "" {
  53. return nil, false
  54. }
  55. db := model.UseDB()
  56. var authToken model.AuthToken
  57. err := db.Where("short_token = ?", shortToken).First(&authToken).Error
  58. if err != nil {
  59. return nil, false
  60. }
  61. if authToken.ExpiredAt < time.Now().Unix() {
  62. DeleteToken(authToken.Token)
  63. return nil, false
  64. }
  65. u := query.User
  66. user, err := u.FirstByID(authToken.UserID)
  67. return user, err == nil
  68. }
  69. type AccessTokenPayload struct {
  70. Token string `json:"token,omitempty"`
  71. ShortToken string `json:"short_token,omitempty"`
  72. }
  73. func GenerateJWT(user *model.User) (*AccessTokenPayload, error) {
  74. now := time.Now()
  75. claims := JWTClaims{
  76. Name: user.Name,
  77. UserID: user.ID,
  78. RegisteredClaims: jwt.RegisteredClaims{
  79. ExpiresAt: jwt.NewNumericDate(now.Add(ExpiredTime)),
  80. IssuedAt: jwt.NewNumericDate(now),
  81. NotBefore: jwt.NewNumericDate(now),
  82. Issuer: "Nginx UI",
  83. Subject: user.Name,
  84. ID: cast.ToString(user.ID),
  85. },
  86. }
  87. unsignedToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  88. signedToken, err := unsignedToken.SignedString([]byte(cSettings.AppSettings.JwtSecret))
  89. if err != nil {
  90. return nil, err
  91. }
  92. // Generate 16-byte short token (16 characters)
  93. shortTokenBytes := make([]byte, 16)
  94. _, err = rand.Read(shortTokenBytes)
  95. if err != nil {
  96. return nil, err
  97. }
  98. // Use base64 URL encoding to get a 16-character string
  99. shortToken := base64.URLEncoding.EncodeToString(shortTokenBytes)[:16]
  100. q := query.AuthToken
  101. err = q.Create(&model.AuthToken{
  102. UserID: user.ID,
  103. Token: signedToken,
  104. ShortToken: shortToken,
  105. ExpiredAt: now.Add(ExpiredTime).Unix(),
  106. })
  107. if err != nil {
  108. return nil, err
  109. }
  110. return &AccessTokenPayload{
  111. Token: signedToken,
  112. ShortToken: shortToken,
  113. }, nil
  114. }
  115. func ValidateJWT(tokenStr string) (claims *JWTClaims, err error) {
  116. if tokenStr == "" {
  117. err = ErrTokenIsEmpty
  118. return
  119. }
  120. token, err := jwt.ParseWithClaims(tokenStr, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
  121. return []byte(cSettings.AppSettings.JwtSecret), nil
  122. })
  123. if err != nil {
  124. return
  125. }
  126. var ok bool
  127. if claims, ok = token.Claims.(*JWTClaims); ok && token.Valid {
  128. return claims, nil
  129. }
  130. return nil, ErrInvalidClaimsType
  131. }