File manager - Edit - /var/www/html/homologBancodetalentos/app/Http/Services/AuthService.php
Back
<?php namespace App\Http\Services; use App\Support\TalentBank\IntegrationCircuitBreaker; use App\Support\TalentBank\IntegrationLog; use Illuminate\Http\Client\ConnectionException; use Illuminate\Http\Client\PendingRequest; use Illuminate\Http\Client\Response; use Illuminate\Http\Request; use Illuminate\Support\Facades\Http; class AuthService { private const IDENTITY_INTEGRATION = 'auth_service'; /** * Converte resposta HTTP da API de cadastro em erros para withErrors(). * Trata 502/503/HTML (proxy Squid, SSO fora) com mensagem clara — não exibe HTML no alerta. */ public static function validationErrorsFromRegisterResponse(Response $response): array { $status = $response->status(); $body = $response->body(); if ($status >= 500 || $status === 0 || self::responseBodyLooksLikeHtmlError($body)) { return ['document' => self::friendlyAuthServiceFailureMessage($status, $body)]; } $json = $response->json(); if (! is_array($json)) { $decoded = json_decode($body, true); $json = is_array($decoded) ? $decoded : null; } if (! is_array($json)) { return ['document' => self::friendlyAuthServiceFailureMessage($status, $body)]; } $errors = self::validationErrorsForWebRedirect($json); $generic = __('validation.validation_error'); if (($errors['document'] ?? '') === $generic && config('app.debug') && $body !== '' && ! self::responseBodyLooksLikeHtmlError($body)) { $errors['document'] = $generic.' (HTTP '.$status.'): '.mb_substr($body, 0, 400); } return $errors; } private static function responseBodyLooksLikeHtmlError(string $body): bool { $head = strtolower(substr(ltrim($body), 0, 400)); return str_contains($head, '<!doctype') || str_contains($head, '<html') || str_contains($head, 'squid'); } private static function friendlyAuthServiceFailureMessage(int $status, string $body): string { $lower = strtolower($body); if (str_contains($lower, 'squid')) { return 'O proxy de rede (Squid) não conseguiu acessar o servidor de cadastro/SSO. Verifique VPN, firewall, ou se AUTH_SERVICE_URL no .env aponta para um endereço alcançável a partir desta máquina (não use URL interna bloqueada pelo proxy).'; } if ($status === 503 || $status === 502 || $status === 504) { return 'Serviço de autenticação indisponível (HTTP '.$status.'). O servidor em AUTH_SERVICE_URL pode estar fora do ar, sobrecarregado ou inacessível pela rede atual.'; } if ($status >= 500) { return 'Erro no servidor de autenticação (HTTP '.$status.'). Tente mais tarde ou confira AUTH_SERVICE_URL e se o serviço SSO está no ar.'; } if (self::responseBodyLooksLikeHtmlError($body)) { return 'A API de cadastro retornou uma página HTML em vez de JSON (URL incorreta, redirect ou bloqueio). Confira AUTH_SERVICE_URL no .env.'; } return __('validation.validation_error'); } /** * Converte resposta 422 da API de usuários em array plano para withErrors(). * Suporta Laravel ({ errors }), { data }, OAuth (error_description), JSON genérico. * * @return array<string, string> */ public static function validationErrorsForWebRedirect(?array $json): array { if (! is_array($json)) { return ['document' => __('validation.validation_error')]; } $fromErrors = self::flattenValidationErrorsNode($json['errors'] ?? null); if ($fromErrors !== []) { return $fromErrors; } $nestedErrors = self::flattenValidationErrorsNode(data_get($json, 'data.errors')); if ($nestedErrors !== []) { return $nestedErrors; } if (isset($json['data']) && is_array($json['data']) && ! array_key_exists('errors', $json['data'])) { $out = []; foreach ($json['data'] as $key => $messages) { if (is_array($messages) && $messages !== []) { $first = $messages[0] ?? ''; if (is_string($first) && $first !== '') { $out[$key] = $first; } } elseif (is_string($messages) && $messages !== '') { $out[$key] = $messages; } } if ($out !== []) { return $out; } } $msg = data_get($json, 'message'); if (is_string($msg) && trim($msg) !== '') { return ['document' => $msg]; } $err = data_get($json, 'error'); if (is_string($err) && trim($err) !== '') { return ['document' => $err]; } $desc = data_get($json, 'error_description'); if (is_string($desc) && trim($desc) !== '') { return ['document' => $desc]; } $detail = data_get($json, 'detail'); if (is_string($detail) && trim($detail) !== '') { return ['document' => $detail]; } return ['document' => __('validation.validation_error')]; } /** * @param mixed $node * @return array<string, string> */ private static function flattenValidationErrorsNode($node): array { if (! is_array($node) || $node === []) { return []; } $out = []; foreach ($node as $key => $messages) { if (! is_string($key) || $key === '') { continue; } if (is_array($messages)) { foreach ($messages as $item) { if (is_string($item) && $item !== '') { $out[$key] = isset($out[$key]) ? $out[$key].' '.$item : $item; break; } } } elseif (is_string($messages) && $messages !== '') { $out[$key] = $messages; } } return $out; } /** * @return array<string, string> */ private function correlationHeaders(): array { if (! function_exists('request') || ! request()) { return []; } $cid = request()->attributes->get('correlation_id'); return is_string($cid) && $cid !== '' ? ['X-Correlation-ID' => $cid] : []; } private function identityBaseUrl(): string { return rtrim((string) env('AUTH_SERVICE_URL'), '/'); } /** * Cliente HTTP para AUTH_SERVICE_URL: timeout, retry só em falha de conexão, proxy vazio em localhost. * * @param array<string, string> $extraHeaders */ private function identityHttp(array $extraHeaders = []): PendingRequest { $headers = array_merge([ 'Accept' => 'application/json', 'App' => (string) env('APP_ID'), ], $this->correlationHeaders(), $extraHeaders); $client = Http::withHeaders($headers) ->timeout((int) config('talent_bank.http_timeout_seconds', 20)) ->retry( (int) config('talent_bank.http_retry_times', 2), (int) config('talent_bank.http_retry_sleep_ms', 350), static function ($exception): bool { return $exception instanceof ConnectionException; } ); if (preg_match('#^https?://(localhost|127\.0\.0\.1)(:\d+)?(/|$)#i', $this->identityBaseUrl())) { $client = $client->withOptions(['proxy' => '']); } return $client; } /** * @return array<string, string> */ private function bearerAuthorizationHeader(Request $request): array { $token = $request->bearerToken(); return (is_string($token) && $token !== '') ? ['Authorization' => 'Bearer '.$token] : []; } public function login(Request $request): Response { return $this->identityCall(function () use ($request) { return $this->identityHttp()->post($this->identityBaseUrl().'/api/login', [ 'grant_type' => 'password', 'client_id' => env('PASSPORT_CLIENT_ID'), 'client_secret' => env('PASSPORT_SECRET'), 'username' => $request->document, 'password' => $request->password, 'scope' => '', ]); }, 'login'); } public function logout(Request $request): Response { return $this->identityCall(function () use ($request) { return $this->identityHttp($this->bearerAuthorizationHeader($request)) ->post($this->identityBaseUrl().'/api/logout'); }, 'logout'); } public function register(Request $request): Response { $payload = $this->registerPayload($request); $extra = $this->bearerAuthorizationHeader($request); return $this->identityCall(function () use ($extra, $payload) { return $this->identityHttp($extra) ->asJson() ->post($this->identityBaseUrl().'/api/user', $payload); }, 'register'); } /** * Apenas campos esperados pelo cadastro SSO — evita enviar vacancies[], logo, _token etc. * * @return array<string, mixed> */ private function registerPayload(Request $request): array { $permissions = $request->input('permissions', []); if (! is_array($permissions)) { $permissions = []; } $document = $request->input('document'); $payload = [ 'document' => $document, 'username' => $document, 'password' => $request->input('password'), 'password_confirmation' => $request->input('password_confirmation'), 'email' => $request->input('email'), 'email_confirmation' => $request->input('email_confirmation'), 'name' => $request->input('name'), 'user_type_id' => (int) ($request->input('user_type_id') ?? 1), 'first_access' => $request->has('first_access') ? (int) $request->input('first_access') : 0, 'permissions' => $permissions, 'module_name' => $request->input('module_name'), ]; $filtered = array_filter( $payload, static function ($value, $key) { if (in_array($key, ['permissions', 'first_access', 'user_type_id'], true)) { return true; } return $value !== null && $value !== ''; }, ARRAY_FILTER_USE_BOTH ); if ($request->filled('password')) { $filtered['password'] = $request->input('password'); $filtered['password_confirmation'] = $request->input('password_confirmation'); } if ($document !== null && $document !== '') { $filtered['document'] = $document; $filtered['username'] = $document; } return $filtered; } public function sendEmail(Request $request): Response { return $this->identityCall(function () use ($request) { return $this->identityHttp() ->post($this->identityBaseUrl().'/api/password/email', $request->all()); }, 'password_email'); } public function tokenValidator(Request $request): Response { return $this->identityCall(function () use ($request) { return $this->identityHttp() ->post($this->identityBaseUrl().'/api/password/token-validator', $request->all()); }, 'password_token_validator'); } public function resetPassword(Request $request): Response { return $this->identityCall(function () use ($request) { return $this->identityHttp() ->post($this->identityBaseUrl().'/api/password/reset', $request->all()); }, 'password_reset'); } public function session(Request $request): Response { return $this->identityCall(function () use ($request) { return $this->identityHttp($this->bearerAuthorizationHeader($request)) ->get($this->identityBaseUrl().'/api/session'); }, 'session'); } private function identityCall(\Closure $callback, string $operation): Response { if (IntegrationCircuitBreaker::isOpen(self::IDENTITY_INTEGRATION)) { IntegrationLog::warning(self::IDENTITY_INTEGRATION, 'circuit_breaker_short_circuit', [ 'operation' => $operation, ]); return Http::response([ 'message' => 'Serviço de autenticação temporariamente indisponível.', ], 503); } try { $response = $callback(); } catch (ConnectionException $e) { IntegrationCircuitBreaker::recordFailure(self::IDENTITY_INTEGRATION); throw $e; } if ($response->serverError() || $response->status() === 429) { IntegrationCircuitBreaker::recordFailure(self::IDENTITY_INTEGRATION); } else { IntegrationCircuitBreaker::recordSuccess(self::IDENTITY_INTEGRATION); } return $response; } }
| ver. 1.4 |
Github
|
.
| PHP 8.3.28 | Generation time: 0.02 |
proxy
|
phpinfo
|
Settings