getPathInfo() === '/api/v1/user/login' && $request->isMethod('POST'); } public function authenticate(Request $request): Passport { $limiter = $this->loginLimiter->create($request->getClientIp() ?? 'unknown'); if (!$limiter->consume(1)->isAccepted()) { throw new TooManyRequestsHttpException(60, 'تعداد تلاش‌های ورود از حد مجاز گذشت'); } $data = json_decode($request->getContent(), true) ?? []; $mobile = trim($data['mobile_number'] ?? ''); $pass = $data['password'] ?? ''; return new Passport( new UserBadge($mobile, fn(string $id) => $this->userRepository->findByMobile($id)), new PasswordCredentials($pass) ); } public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response { $user = $token->getUser(); if (!$user->isStaff()) { return new JsonResponse([ 'success' => false, 'data' => null, 'errors' => [['code' => ErrorCodes::ERR_AUTH_006, 'message' => ErrorCodes::message(ErrorCodes::ERR_AUTH_006)]], ], 403); } $accessToken = $this->jwtManager->create($user); $rawToken = bin2hex(random_bytes(32)); $cacheKey = 'refresh_' . hash('sha256', $rawToken); $item = $this->cache->getItem($cacheKey); $item->set((string) $user->getId()); $item->expiresAfter($this->refreshTokenTtl); $this->cache->save($item); $this->logger->info('login_success', [ 'user_id' => $user->getId(), 'ip' => $request->getClientIp(), 'method' => 'password', ]); return new JsonResponse([ 'access_token' => $accessToken, 'refresh_token' => $rawToken, 'token_type' => 'Bearer', 'expires_in' => 900, 'refresh_token_expires_in' => $this->refreshTokenTtl, ]); } public function onAuthenticationFailure(Request $request, AuthenticationException $exception): Response { $this->logger->warning('login_failed', [ 'ip' => $request->getClientIp(), 'reason' => $exception->getMessage(), ]); return new JsonResponse([ 'success' => false, 'data' => null, 'errors' => [['code' => ErrorCodes::ERR_AUTH_005, 'message' => ErrorCodes::message(ErrorCodes::ERR_AUTH_005)]], ], 401); } }