auth.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package user
  2. import (
  3. "github.com/0xJacky/Nginx-UI/api"
  4. "github.com/0xJacky/Nginx-UI/internal/logger"
  5. "github.com/0xJacky/Nginx-UI/internal/user"
  6. "github.com/0xJacky/Nginx-UI/query"
  7. "github.com/0xJacky/Nginx-UI/settings"
  8. "github.com/gin-gonic/gin"
  9. "github.com/pkg/errors"
  10. "net/http"
  11. "sync"
  12. "time"
  13. )
  14. var mutex = &sync.Mutex{}
  15. type LoginUser struct {
  16. Name string `json:"name" binding:"required,max=255"`
  17. Password string `json:"password" binding:"required,max=255"`
  18. }
  19. const (
  20. ErrPasswordIncorrect = 4031
  21. ErrMaxAttempts = 4291
  22. ErrUserBanned = 4033
  23. )
  24. type LoginResponse struct {
  25. Message string `json:"message"`
  26. Error string `json:"error,omitempty"`
  27. Code int `json:"code"`
  28. Token string `json:"token,omitempty"`
  29. }
  30. func Login(c *gin.Context) {
  31. // make sure that only one request is processed at a time
  32. mutex.Lock()
  33. defer mutex.Unlock()
  34. // check if the ip is banned
  35. clientIP := c.ClientIP()
  36. b := query.BanIP
  37. banIP, _ := b.Where(b.IP.Eq(clientIP),
  38. b.ExpiredAt.Gte(time.Now().Unix()),
  39. b.Attempts.Gte(settings.AuthSettings.MaxAttempts),
  40. ).Count()
  41. if banIP > 0 {
  42. c.JSON(http.StatusTooManyRequests, LoginResponse{
  43. Message: "Max attempts",
  44. Code: ErrMaxAttempts,
  45. })
  46. return
  47. }
  48. var json LoginUser
  49. ok := api.BindAndValid(c, &json)
  50. if !ok {
  51. return
  52. }
  53. u, err := user.Login(json.Name, json.Password)
  54. if err != nil {
  55. // time.Sleep(5 * time.Second)
  56. switch {
  57. case errors.Is(err, user.ErrPasswordIncorrect):
  58. c.JSON(http.StatusForbidden, LoginResponse{
  59. Message: "Password incorrect",
  60. Code: ErrPasswordIncorrect,
  61. })
  62. case errors.Is(err, user.ErrUserBanned):
  63. c.JSON(http.StatusForbidden, LoginResponse{
  64. Message: "The user is banned",
  65. Code: ErrUserBanned,
  66. })
  67. default:
  68. api.ErrHandler(c, err)
  69. }
  70. user.BanIP(clientIP)
  71. return
  72. }
  73. // login success, clear banned record
  74. _, _ = b.Where(b.IP.Eq(clientIP)).Delete()
  75. logger.Info("[User Login]", u.Name)
  76. token, err := user.GenerateJWT(u.Name)
  77. if err != nil {
  78. c.JSON(http.StatusInternalServerError, LoginResponse{
  79. Message: err.Error(),
  80. })
  81. return
  82. }
  83. c.JSON(http.StatusOK, LoginResponse{
  84. Message: "ok",
  85. Token: token,
  86. })
  87. }
  88. func Logout(c *gin.Context) {
  89. token := c.GetHeader("Authorization")
  90. if token != "" {
  91. err := user.DeleteToken(token)
  92. if err != nil {
  93. c.JSON(http.StatusInternalServerError, gin.H{
  94. "message": err.Error(),
  95. })
  96. return
  97. }
  98. }
  99. c.JSON(http.StatusNoContent, nil)
  100. }