tzkmx
11/7/2019 - 10:40 PM

Middleware para extender token y cookie en Laravel

Middleware para extender token y cookie en Laravel

<?php

namespace App\Http\Middleware;

use App\Auth\CreateTokenService;
use App\Http\Controllers\Auth\CreateTokenCookie;
use Closure;
use Illuminate\Support\Facades\Log;
use ReallySimpleJWT\Exception\ValidateException;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Http\Request;

class ExtendCookieToken
{
    use CreateTokenCookie;
    /** @var CreateTokenService */
    protected $createTokenService;

    /**
     * ExtendCookieToken constructor.
     * @param CreateTokenService $tokenService
     */
    public function __construct(CreateTokenService $tokenService)
    {
        $this->createTokenService = $tokenService;
    }

    /**
     * Handle an incoming request.
     *
     * @param  Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        try {
            return $this->extend($response, $request);
        } catch (ValidateException $e) {
            Log::error($e->getMessage());
            return $response;
        }
    }

    /**
     * Encrypt the cookies on an outgoing response.
     *
     * @param Response $response
     * @param Request $request
     * @return Response
     * @throws ValidateException
     */
    protected function extend(Response $response, Request $request): Response
    {
        if (strpos($request->getUri(), 'logout')) {
            return $response;
        }
        try {
            $cookie = $this->searchCookieToken($response);

            if (is_null($cookie)) {
                return $this->createCookieIfNotPresent(
                    $request,
                    $response
                );
            }

            $token = $cookie->getValue() ?? '';
            if ($token === '') {
                return $response;
            }

            $newToken = $this->createTokenService->regenerateToken($token);
            $response->headers->setCookie(
                $this->duplicateWithNewExpireTime($cookie, $newToken)
            );
            Log::info('cookies', $response->headers->getCookies());
            return $response;
        } catch (ValidateException $e) {
            return $response;
        }
    }

    protected function createCookieIfNotPresent(
        Request $request,
        Response $response
    ): Response
    {
        $user = $request->user();
        $cookie = $this->createTokenCookie($user);
        $response->headers->setCookie($cookie);
        return $response;
    }

    /**
     * @param Response $response
     * @return Cookie|null
     */
    protected function searchCookieToken(Response $response): ?Cookie
    {
        $cookies = $response->headers->getCookies();
        if (empty($cookies)) {
            return null;
        }
        foreach ($cookies as $cookie) {
            if ($cookie->getName() === 'token') {
                return $cookie;
            }
        }
        return null;
    }

    /**
     * Duplicate a cookie with a new value.
     *
     * @param  Cookie  $cookie
     * @param  string  $value
     * @param int|null $newExpire
     * @return Cookie
     */
    protected function duplicateWithNewExpireTime(
        Cookie $cookie,
        string $value,
        int $newExpire = null
    ) {
        $defaultExpireTime = time() + $this->createTokenService->getTokenExpireTime();
        $expires = is_null($newExpire) ? $defaultExpireTime : $newExpire;
        return new Cookie(
            $cookie->getName(), $value, $expires,
            $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(),
            $cookie->isHttpOnly(), $cookie->isRaw(), $cookie->getSameSite()
        );
    }
}