get(key: 'JWT_ISSUER'); self::$algorithm = $Config->get(key: 'JWT_ALGO'); self::$secretKey = $Config->get(key: 'JWT_SECRET'); self::$expiration = $Config->get(key: 'JWT_EXPIRATION'); } /** * Gera um token JWT com base em um payload e nas configurações da aplicação. * * Este método cria um token JWT válido a partir de um array de dados fornecido (`$payload`), * adicionando automaticamente metadados essenciais como a data de emissão, a data de expiração e o emissor. * * O processo detalhado inclui: * 1. **Inicialização:** Chama o método `init()` para garantir que todas as configurações do JWT * (chave secreta, algoritmo, etc.) estejam carregadas. * 2. **Definição dos Timestamps:** Calcula o timestamp de emissão (`iat`) e o de expiração (`exp`) * com base no tempo de expiração definido nas configurações. * 3. **Montagem do Payload:** Adiciona as chaves `iat`, `exp` e `iss` (emissor) ao array `$payload`. * 4. **Codificação do Token:** Utiliza a biblioteca `JWT::encode()` para codificar o payload * com a chave secreta e o algoritmo definidos nas configurações. * * @param array $payload Um array associativo contendo os dados personalizados que serão incluídos no token. * @return array O token JWT gerado como um array. */ public static function generateToken(array $payload): array { // Carrega as informações do arquivo de configuração self::init(); // Define data de emissão e calcula a data de expiração do token $expiration = self::$expiration; $createdAt = (new DateTime())->getTimestamp(); $expireAt = (new DateTime())->modify(modifier: "+{$expiration} seconds")->getTimestamp(); // Adiciona data de criação ao payload $payload['iat'] = $createdAt; // Adiciona a expiração ao payload $payload['exp'] = $expireAt; // Adiciona o emissor ao payload $payload['iss'] = self::$issuer; return [ 'token' => JWT::encode(payload: $payload, key: self::$secretKey, alg: self::$algorithm), 'expires_at' => (new DateTime())->setTimestamp(timestamp: $expireAt)->format(format: 'Y-m-d H:i:s') ]; } /** * Valida um token JWT e retorna o objeto de payload decodificado. * * Este método estático decodifica e valida um token JWT fornecido, utilizando * a chave secreta e o algoritmo de criptografia configurados na classe. * * #### Como funciona: * 1. Recebe o token (`$token`) que precisa ser validado. * 2. Usa a biblioteca `JWT::decode()` para decodificar o token. * 3. Para a decodificação, ele cria uma nova instância de `Key`, passando * a chave secreta (`self::$secretKey`) e o algoritmo (`self::$algorithm`). * Isso garante que o token só será decodificado se tiver sido assinado com a chave e algoritmo corretos. * 4. Se o token for válido e a assinatura corresponder, a função retorna o payload do token * como um objeto. * 5. Se o token for inválido (por exemplo, assinatura incorreta, expirado ou formato incorreto), * a biblioteca JWT lançará uma exceção, que a função que chama este método deve capturar. * * @param string $token O token JWT a ser validado e decodificado. * @return object O objeto de payload decodificado do token. */ public static function validateToken(string $token): object { // Inicializa as configurações se ainda não estiverem definidas if (!isset(self::$secretKey)) { self::init(); } return JWT::decode(jwt: $token, keyOrKeyArray: new Key(keyMaterial: self::$secretKey, algorithm: self::$algorithm)); } /** * Decodifica um token JWT e retorna seu payload como um array associativo. * * Este método estático é responsável por decodificar e validar um token JWT. Antes de decodificar, ele garante que as configurações de chave secreta e algoritmo (`self::$secretKey` e `self::$algorithm`) já foram inicializadas chamando o método `init()` se necessário. * * #### Como Funciona: * 1. **Inicialização:** Primeiro, verifica se a chave secreta (`self::$secretKey`) já foi carregada. Se não, ele chama `self::init()` para carregar as configurações de um arquivo externo. * 2. **Decodificação:** Usa a biblioteca `Firebase\JWT\JWT::decode()` para decodificar o token fornecido. O método passa a chave secreta e o algoritmo para verificar a assinatura do token. * 3. **Conversão:** O payload decodificado, que por padrão é um objeto, é convertido para uma string JSON e depois para um array associativo, o que facilita o acesso aos dados. * 4. **Retorno:** Retorna o payload do token como um array associativo. Se o token for inválido (assinatura incorreta, expirado, etc.), a biblioteca JWT lançará uma exceção, que a função que chama este método deve capturar. * * @param string $token O token JWT a ser decodificado. * @return array O payload do token decodificado como um array associativo. */ public static function decode(?string $token): array { // Inicializa as configurações se ainda não estiverem definidas if (!isset(self::$secretKey)) { self::init(); } if($token === null) { return []; } $decoded = JWT::decode(jwt: $token, keyOrKeyArray: new Key(keyMaterial: self::$secretKey, algorithm: self::$algorithm)); return json_decode(json: json_encode(value: $decoded), associative: true); } /** * Extrai o token de autenticação do tipo 'Bearer' do cabeçalho da requisição HTTP. * * Este método estático é um utilitário projetado para buscar um token JWT (JSON Web Token) * que é enviado no cabeçalho `Authorization`. Ele é robusto o suficiente para verificar * o token em diferentes superglobais do PHP, dependendo da configuração do servidor web. * * #### Fluxo de Busca: * 1. Primeiro, tenta obter o cabeçalho `Authorization` diretamente da superglobal `$_SERVER`. * 2. Em seguida, tenta a chave `HTTP_AUTHORIZATION`, que é um nome de variável comum em alguns ambientes. * 3. Por último, usa a função `apache_request_headers()` para tentar obter o cabeçalho, caso as * superglobais não estejam preenchidas. Isso garante compatibilidade com servidores Apache onde o cabeçalho pode não ser exposto. * 4. Se o cabeçalho for encontrado, o valor é sanitizado (removendo espaços em branco) e a busca continua. * 5. Se nenhum cabeçalho de autenticação for encontrado, o método retorna `null`. * * #### Extração do Token: * - Depois de encontrar o cabeçalho, o método usa uma expressão regular (`/Bearer\s(\S+)/`) * para verificar se o valor do cabeçalho está no formato `Bearer `. * - Se o padrão corresponder, ele extrai e retorna a string do token. * - Se o padrão não corresponder, o método retorna `null`. * * @return string|null O token de autenticação do tipo 'Bearer' como uma string, ou `null` * se o cabeçalho não for encontrado ou não estiver no formato esperado. */ public static function getBearerToken(): ?string { if (!isset(self::$secretKey)) { self::init(); } // Tenta pegar o header de todas as fontes possíveis $headers = $_SERVER['Authorization'] ?? $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? (function_exists(function: 'apache_request_headers') ? apache_request_headers() : []); // Se veio do apache_request_headers, normaliza chaves if (is_array(value: $headers)) { $headers = array_change_key_case(array: $headers, case: CASE_LOWER); $headers = $headers['authorization'] ?? ''; } $headers = trim(string: $headers); if ($headers && preg_match(pattern: '/Bearer\s(\S+)/', subject: $headers, matches: $matches)) { return $matches[1]; } return null; } }