AdvancedRateLimiterServices.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. <?php
  2. namespace App\Services;
  3. use Carbon\Carbon;
  4. use Illuminate\Http\Request;
  5. use Illuminate\Support\Facades\Cache;
  6. class AdvancedRateLimiterServices
  7. {
  8. /**
  9. * The maximum number of attempts to allow.
  10. *
  11. * @var int
  12. */
  13. protected $maxAttempts = 3;
  14. /**
  15. * The number of minutes to throttle for.
  16. *
  17. * @var int|float|int[]|float[]
  18. */
  19. protected $decayMinutes = [30, 60, 120];
  20. /**
  21. * 登录失败记录
  22. * @param Request $request
  23. * @param bool $maxAttempts
  24. * @param bool $decayMinutes
  25. * @return bool
  26. * Author: Mead
  27. */
  28. public function main(Request $request, $maxAttempts = false, $decayMinutes = false)
  29. {
  30. if (!$maxAttempts) {
  31. $maxAttempts = $this->maxAttempts;
  32. }
  33. if (!$decayMinutes) {
  34. $decayMinutes = $this->decayMinutes;
  35. }
  36. $key = $this->throttleKey($request);
  37. if (!Cache::has($key . ':step')) {
  38. Cache::add($key . ':step', 1, Carbon::parse(date('Y-m-d'))->addDays(1));
  39. } else {
  40. Cache::increment($key . ':step');
  41. }
  42. $nums = Cache::get($key . ':step', 1);
  43. if (!($nums % $maxAttempts)) {
  44. $step = $nums / $maxAttempts;
  45. $index = $step <= count($decayMinutes) ? ($step - 1) : false;
  46. if ($index === false) {
  47. $minutes = false;
  48. } else {
  49. $minutes = $decayMinutes[$index];
  50. }
  51. $time = str2arr(Cache::get($key . ':timer', ''));
  52. Cache::put($key . ':timer', php2js([
  53. 'time' => $minutes ? Carbon::now()->addMinutes($minutes)->toDateTimeString() : false,
  54. 'nums' => array_key_exists('time', $time) ? $time['time'] + 1 : 1
  55. ]), $minutes ? Carbon::now()->addMinutes($minutes) : Carbon::parse(date('Y-m-d'))->addDays(1));
  56. }
  57. return true;
  58. }
  59. /**
  60. * 获取key
  61. */
  62. public function throttleKey(Request $request)
  63. {
  64. return sha1(implode('|', array_merge(
  65. [$request->getMethod()],
  66. [$request->getHost(), $request->getUri(), $request->getClientIp()]
  67. )));
  68. }
  69. /**
  70. * 是否可以登录
  71. * @param Request $request
  72. * @return bool|string
  73. * Author: Mead
  74. */
  75. public function isLogin(Request $request)
  76. {
  77. $key = $this->throttleKey($request);
  78. $msg = false;
  79. if (Cache::has($key . ':timer')) {
  80. $msg = '今天尝试次数太多,请明天再试。';
  81. $re = js2php(Cache::get($key . ':timer', ''));
  82. if (array_key_exists('time', $re)) {
  83. if ($re['time'] != false) {
  84. $minutes = Carbon::parse($re['time'])->diffInMinutes(Carbon::now()) + 1;
  85. $msg = "尝试次数太多,请{$minutes}分钟后再试。";
  86. }
  87. }
  88. }
  89. return $msg;
  90. }
  91. /**
  92. * 清楚缓存
  93. * @param Request $request
  94. * Author: Mead
  95. */
  96. public function clear(Request $request)
  97. {
  98. $key = $this->throttleKey($request);
  99. Cache::forget($key . ':step');
  100. }
  101. }