user.go 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package services
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. )
  7. var (
  8. // 登录尝试记录
  9. loginAttempts = struct {
  10. sync.RWMutex
  11. m map[string]AttemptInfo
  12. }{m: make(map[string]AttemptInfo)}
  13. )
  14. // AttemptInfo 登录尝试信息
  15. type AttemptInfo struct {
  16. Count int
  17. FirstTry time.Time
  18. LockedUntil *time.Time
  19. }
  20. // CheckLoginAttempts 检查登录尝试次数
  21. func CheckLoginAttempts(identifier string) (bool, string) {
  22. loginAttempts.RLock()
  23. info, exists := loginAttempts.m[identifier]
  24. loginAttempts.RUnlock()
  25. if !exists {
  26. return true, ""
  27. }
  28. // 检查是否被锁定
  29. if info.LockedUntil != nil && time.Now().Before(*info.LockedUntil) {
  30. remaining := info.LockedUntil.Sub(time.Now())
  31. return false, fmt.Sprintf("账户已锁定,请%.0f分钟后再试", remaining.Minutes())
  32. }
  33. // 检查尝试次数
  34. if info.Count >= 5 {
  35. // 锁定30分钟
  36. lockedUntil := time.Now().Add(30 * time.Minute)
  37. info.LockedUntil = &lockedUntil
  38. loginAttempts.Lock()
  39. loginAttempts.m[identifier] = info
  40. loginAttempts.Unlock()
  41. return false, "尝试次数过多,账户已锁定30分钟"
  42. }
  43. return true, ""
  44. }
  45. // RecordLoginAttempt 记录登录尝试
  46. func RecordLoginAttempt(identifier string, success bool) {
  47. loginAttempts.Lock()
  48. defer loginAttempts.Unlock()
  49. info, exists := loginAttempts.m[identifier]
  50. if success {
  51. // 登录成功,清除记录
  52. delete(loginAttempts.m, identifier)
  53. return
  54. }
  55. if !exists {
  56. // 第一次失败
  57. loginAttempts.m[identifier] = AttemptInfo{
  58. Count: 1,
  59. FirstTry: time.Now(),
  60. }
  61. } else {
  62. // 增加失败次数
  63. info.Count++
  64. loginAttempts.m[identifier] = info
  65. // 如果30分钟内失败5次,锁定账户
  66. if info.Count >= 5 && time.Since(info.FirstTry) <= 30*time.Minute {
  67. lockedUntil := time.Now().Add(30 * time.Minute)
  68. info.LockedUntil = &lockedUntil
  69. loginAttempts.m[identifier] = info
  70. }
  71. }
  72. // 清理30分钟前的记录
  73. for key, attemptInfo := range loginAttempts.m {
  74. if time.Since(attemptInfo.FirstTry) > 30*time.Minute {
  75. delete(loginAttempts.m, key)
  76. }
  77. }
  78. }