/** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @param int $maxAttempts * @param int $decayMinutes * @return mixed */ public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1) { $key = $this->resolveRequestSignature($request); if ($this->limiter->tooManyAttempts($key, $maxAttempts, $decayMinutes)) { return new Response('Too Many Attempts.', 429, ['Retry-After' => $this->limiter->availableIn($key), 'X-RateLimit-Limit' => $maxAttempts, 'X-RateLimit-Remaining' => 0]); } $this->limiter->hit($key, $decayMinutes); return $next($request)->withHeaders(['X-RateLimit-Limit' => $maxAttempts, 'X-RateLimit-Remaining' => $maxAttempts - $this->limiter->attempts($key) + 1]); }
/** * Calculate the number of remaining attempts. * * @param string $key * @param int $maxAttempts * @param int|null $retryAfter * @return int */ protected function calculateRemainingAttempts($key, $maxAttempts, $retryAfter = null) { if (!is_null($retryAfter)) { return 0; } return $this->limiter->retriesLeft($key, $maxAttempts); }
public function postSendVerify($type = null, RateLimiter $rateLimiter) { $user = auth()->user(); $request = request(); $response = response(); if (!$type) { $type = $request->input('type'); } if ($type != 'phone' && $type != 'email') { $response->json(['status' => false, 'message' => '发送失败,Type参数错误!']); } $typeValue = $request->input('input_value'); if ($type == 'email') { if ($typeValue == $user->email || !is_email($typeValue) || strlen($typeValue) > 64) { return $response->json(['status' => false, 'message' => '请输入正确的新邮箱']); } } elseif ($type == 'phone') { if ($typeValue == $user->phone || !is_phone($typeValue)) { return $response->json(['status' => false, 'message' => '请输入正确的新手机号']); } } // 60秒发送一次 $sessionKey = 'send_verify_last_time'; $sessionKey .= ".change.{$type}"; $sessionValue = session($sessionKey); $currentTime = time(); if ($sessionValue && $sessionValue + 60 > $currentTime) { return $response->json(['status' => false, 'message' => '发送失败,请不要频繁获取验证码']); } // 一个IP一个小时可以发送10次 $rateLimiterKey = 'send_verify_rate_limiter'; $rateLimiterKey .= ":change:{$type}_" . $user->id; if ($rateLimiter->tooManyAttempts($rateLimiterKey, 60, 10)) { return $response->json(['status' => false, 'message' => '当前网络环境获取已达上限,请一小时后再试']); } if (User::hasBeenUsed($type, $typeValue, true)->exists()) { $typeName = $type == 'phone' ? '手机号' : '邮箱'; return $response->json(['status' => false, 'message' => '此' . $typeName . '已被其他用户使用']); } $code = rand(100000, 999999); $value = ['type' => $type, 'code' => $code, 'value' => $typeValue, 'attempt' => 0, 'user_id' => $user->id]; $cacheKey = md5("send_verify_detail.change.{$typeValue}" . config('key')); if ($type == 'phone') { require app_path('Services/Taobao/TopSdk.php'); $status = sendSms('phone_change', $typeValue, ['code' => $code, 'product' => '积木']); } elseif ($type == 'email') { $vars = ['email' => $typeValue, 'code' => $code, 'link' => url('account/set/change-confirm') . '?key=' . urlencode($cacheKey)]; $view = 'user.set.change_verify_mail'; $status = \Mail::send($view, $vars, function ($message) use($typeValue) { $message->to($typeValue); $message->subject('[积木] 邮箱绑定验证码'); }); } if (empty($status)) { $status = false; } else { Cache::put($cacheKey, $value, 60); session([$sessionKey => $currentTime]); $rateLimiter->hit($rateLimiterKey); } $typeName = $type == 'phone' ? '短信' : '邮件'; return $response->json(['status' => (bool) $status, 'message' => $status ? '' : 'Oh. 验证' . $typeName . '发送失败,请稍后重试']); }
/** * Calculate the number of remaining attempts. * * @param string $key * @param int $maxAttempts * @return int */ protected function calculateRemainingAttempts($key, $maxAttempts) { return $maxAttempts - $this->limiter->attempts($key) + 1; }
/** * Clear the login locks for the given user credentials. * * @return void */ public function clearLoginAttempts() { $this->cacheLimiter->clear($this->getUniqueLoginKey()); }
public function postSendVerify($type = null, RateLimiter $rateLimiter) { $request = request(); $response = response(); if (!$type) { $type = $request->input('type'); } if ($type != 'register' && $type != 'forgot_password') { $response->json(['status' => false, 'message' => '发送失败,Type参数错误!']); } $identifier = $request->input('identifier'); if (!is_email($identifier) || strlen($identifier) > 64) { if (!is_phone($identifier)) { return $response->json(['status' => false, 'message' => '请输入正确的手机号或邮箱']); } $verifyType = 'phone'; } else { $verifyType = 'email'; } // 60秒发送一次 $sessionKey = 'send_verify_last_time'; $sessionKey .= ".{$type}.{$verifyType}"; $sessionValue = session($sessionKey); $currentTime = time(); if ($sessionValue && $sessionValue + 60 > $currentTime) { return $response->json(['status' => false, 'message' => '发送失败,请不要频繁获取验证码']); } // 一个IP一个小时可以发送20次 $rateLimiterKey = 'send_verify_rate_limiter'; $rateLimiterKey .= ":{$type}:{$verifyType}_" . request()->ip(); if ($rateLimiter->tooManyAttempts($rateLimiterKey, 60, 20)) { return $response->json(['status' => false, 'message' => '当前网络环境获取已达上限,请一小时后再试']); } if ($type == 'register') { if (User::hasBeenUsed($verifyType, $identifier, true)->exists()) { $verifyTypeName = $verifyType == 'phone' ? '手机号' : '邮箱'; $loginUrl = url('account/login', [$identifier]); $forgotPasswordUrl = url('account/forgot-password', [$identifier]); return $response->json(['status' => false, 'message' => '此' . $verifyTypeName . '已被注册,你可以 <a href="' . $loginUrl . '">尝试登陆</a> 或 <a href="' . $forgotPasswordUrl . '">找回密码</a>']); } } elseif ($type == 'forgot_password') { if (!User::hasBeenUsed($verifyType, $identifier, false)->exists()) { $verifyTypeName = $verifyType == 'phone' ? '手机号' : '邮箱'; $createUrl = url('account/create', [$identifier]); return $response->json(['status' => false, 'message' => '此' . $verifyTypeName . '还没注册,<a href="' . $createUrl . '">现在去注册</a>']); } } $code = rand(100000, 999999); $value = ['type' => $type, 'code' => $code, 'identifier' => $identifier, 'verify_type' => $verifyType, 'attempt' => 0]; $cacheKey = md5("send_verify_detail.{$type}.{$identifier}" . config('key')); if ($verifyType == 'phone') { require app_path('Services/Taobao/TopSdk.php'); $status = sendSms($type . '_verify', $identifier, ['code' => $code, 'product' => '积木']); } elseif ($verifyType == 'email') { $action = $type == 'register' ? 'create' : 'forgot-password'; $vars = ['email' => $identifier, 'code' => $code, 'link' => url('account/' . $action) . '?key=' . urlencode($cacheKey)]; $view = 'user.account.' . $type . '_verify_mail'; $subject = $type == 'register' ? '[积木] 账户注册验证码' : '[积木] 账户密码找回验证码'; $status = \Mail::send($view, $vars, function ($message) use($identifier, $subject) { $message->to($identifier); $message->subject($subject); }); } if (empty($status)) { $status = false; } else { Cache::put($cacheKey, $value, 60); session([$sessionKey => $currentTime]); $rateLimiter->hit($rateLimiterKey); } $typeName = $verifyType == 'phone' ? '短信' : '邮件'; return $response->json(['status' => (bool) $status, 'message' => $status ? '' : 'Oh. 验证' . $typeName . '发送失败,请稍后重试']); }