Saltar al contenido

¿La autenticación predeterminada de Sanctum y Laravel es la misma si no se usa para tokens?

Solución:

Por lo tanto, si los tokens nunca se usan, Sanctum es básicamente el mismo que el método de autenticación predeterminado, ¿estoy en lo correcto?

Sí, debajo del capó usa la autenticación predeterminada de laravel.

Echando un vistazo a la guardia del santuario (debajo del código tomado de github. Se comprometió por última vez el 11 de abril, santuario 2.x)

<?php

namespace LaravelSanctum;

use IlluminateContractsAuthFactory as AuthFactory;
use IlluminateHttpRequest;

class Guard
{
    /**
     * The authentication factory implementation.
     *
     * @var IlluminateContractsAuthFactory
     */
    protected $auth;

    /**
     * The number of minutes tokens should be allowed to remain valid.
     *
     * @var int
     */
    protected $expiration;

    /**
     * Create a new guard instance.
     *
     * @param  IlluminateContractsAuthFactory  $auth
     * @param  int  $expiration
     * @return void
     */
    public function __construct(AuthFactory $auth, $expiration = null)
    {
        $this->auth = $auth;
        $this->expiration = $expiration;
    }

    /**
     * Retrieve the authenticated user for the incoming request.
     *
     * @param  IlluminateHttpRequest  $request
     * @return mixed
     */
    public function __invoke(Request $request)
    {
        if ($user = $this->auth->guard(config('sanctum.guard', 'web'))->user()) {
            return $this->supportsTokens($user)
                        ? $user->withAccessToken(new TransientToken)
                        : $user;
        }

        if ($token = $request->bearerToken()) {
            $model = Sanctum::$personalAccessTokenModel;

            $accessToken = $model::findToken($token);

            if (! $accessToken ||
                ($this->expiration &&
                 $accessToken->created_at->lte(now()->subMinutes($this->expiration)))) {
                return;
            }

            return $this->supportsTokens($accessToken->tokenable) ? $accessToken->tokenable->withAccessToken(
                tap($accessToken->forceFill(['last_used_at' => now()]))->save()
            ) : null;
        }
    }

    /**
     * Determine if the tokenable model supports API tokens.
     *
     * @param  mixed  $tokenable
     * @return bool
     */
    protected function supportsTokens($tokenable = null)
    {
        return $tokenable && in_array(HasApiTokens::class, class_uses_recursive(
            get_class($tokenable)
        ));
    }
}

Si marca el _invoke() método,

    if ($user = $this->auth->guard(config('sanctum.guard', 'web'))->user()) {
        return $this->supportsTokens($user)
                    ? $user->withAccessToken(new TransientToken)
                    : $user;
    }

el usuario autenticado se encuentra usando

$user = $this->auth->guard(config('sanctum.guard', 'web'))->user()

Después de verificar el archivo de configuración de sanctum, no hay sanctum.guard config actualmente (probablemente esté destinado a alguna versión futura), por lo que sanctum comprueba con el web guard de forma predeterminada, por lo que básicamente hace lo mismo que sus rutas web predeterminadas.

Pero has entendido mal el uso de Sanctum. Sanctum es para la autenticación de API y no para la autenticación web (aunque también se puede utilizar la autenticación web). La autenticación sin token de Sanctum es para que sus SPA puedan usar la misma API que las aplicaciones móviles (que usan autenticación de token) sin necesidad de tokens y brindando los beneficios de csrf y autenticación basada en sesión.

Para ayudarlo a comprender mejor, suponga que ha creado una API que usa tokens (si ya está usando sanctum para tokens, eso simplifica las cosas) para la autenticación. Ahora desea construir un SPA (que puede construirse dentro del proyecto laravel en sí, o en un proyecto separado, en el mismo dominio o en un dominio diferente) que usará las mismas API, pero como esto lo creará usted, es un sitio confiable, por lo que no desea que use tokens, sino que use la autenticación basada en sesión predeterminada de laravel junto con la protección csrf mientras también usa las mismas rutas api. El SPA se comunicará con el servidor a través de ajax. También desea asegurarse de que solo su SPA pueda usar la autenticación basada en sesiones y no permita que otros sitios de terceros la usen.

Así que aquí es donde entra Sanctum. Solo tendría que agregar el middleware de Sanctum a su api grupo de ruta en app/Http/Kernel.php

use LaravelSanctumHttpMiddlewareEnsureFrontendRequestsAreStateful;

'api' => [
    EnsureFrontendRequestsAreStateful::class,
    'throttle:60,1',
    IlluminateRoutingMiddlewareSubstituteBindings::class,
],

Luego configure sanctum para permitir el dominio de su SPA y configure cors (consulte los documentos para saber cómo hacer esto). Luego solo agrega el auth:sanctum middleware a su ruta y habrá terminado con la configuración del lado del servidor.

Ahora, estas rutas autenticarán a los usuarios si la solicitud tiene un token o si tiene estado (cookie de sesión).

Ahora su SPA puede comunicarse con su API sin tokens.

Para obtener protección csrf, llame al csrf-cookie Solicite primero, esto configurará un token csrf en sus cookies, y axios lo adjuntará automáticamente a las solicitudes posteriores.

axios.get('/sanctum/csrf-cookie').then(response => {
    // Login...
})

¿Cuál es la diferencia entre sanctum y pasaporte ya que hacen lo mismo pero se dice que Sanctum es ligero?

Bueno, es como dice, Sanctum es liviano. Esto se debe a que Passport proporciona una funcionalidad completa de Oauth, mientras que Sanctum solo se enfoca en crear y administrar tokens. Para explicar Oauth de una manera simple, debe haber visto esos Sign in with Google, Sign in with Facebook, Sign in with Github en diferentes sitios, y luego puede iniciar sesión en esos sitios usando su cuenta de google / facebook / github. Esto es posible porque Google, Facebook y Github proporcionan la funcionalidad Oauth (solo un ejemplo simple, sin entrar en demasiados detalles). Para la mayoría de los sitios web, realmente no necesita Passport, ya que proporciona muchas funciones que no necesita. Para una autenticación de API simple, Sanctum es más que suficiente

NOTA: Esta respuesta es para Laravel Sanctum + SPA del mismo dominio

Para agregar a estas respuestas, la autenticación predeterminada de Laravel usa la web guard, por lo que debe usar eso para sus rutas de autenticación (para la aplicación SPA del mismo dominio).

Por ejemplo, puede crear sus propias rutas que apunten a la ruta de Laravel. RegistersUsers rasgo y AuthenticatesUsers rasgo:

web.php

Route::group(['middleware' => ['guest', 'throttle:10,5']], function () {
    Route::post('register', 'Auth[email protected]')->name('register');
    Route::post('login', 'Auth[email protected]')->name('login');

    Route::post('password/email', 'Auth[email protected]');
    Route::post('password/reset', 'Auth[email protected]');

    Route::post('email/verify/{user}', 'Auth[email protected]')->name('verification.verify');
    Route::post('email/resend', 'Auth[email protected]');

    Route::post('oauth/{driver}', 'Auth[email protected]')->name('oauth.redirect');
    Route::get('oauth/{driver}/callback', 'Auth[email protected]')->name('oauth.callback');
});

Route::post('logout', 'Auth[email protected]')->name('logout');

Pero asegúrate de que estén en el web.php expediente. Por ejemplo, si están en el api.php archivo, vi algunos errores extraños sobre session store not on request y RequestGuard::logout() no es una función. Creo que esto tiene algo que ver con la protección de autenticación predeterminada a través de $this->guard() en los rasgos de autenticación, y algo que ver con api.php‘s /api prefijo.

los /api prefijo parecía relacionado porque si usa el paquete compositor Ziggy para lograr route('login') y route('logout'), en realidad resuelven /api/login y /api/logout.

Sospecho que eso causó un problema con Sanctum. La solución fue asegurarse de que las rutas estuvieran en web.php. Una persona puede reproducir este error si su configuración es similar, o por ejemplo, si tiene Auth::routes() declarado en api.php.

Revisa tu Kernel.php (debería ser así):

protected $middlewareGroups = [
    'web' => [
        AppHttpMiddlewareEncryptCookies::class,
        IlluminateCookieMiddlewareAddQueuedCookiesToResponse::class,
        IlluminateSessionMiddlewareStartSession::class,
        // IlluminateSessionMiddlewareAuthenticateSession::class,
        IlluminateViewMiddlewareShareErrorsFromSession::class,
        AppHttpMiddlewareVerifyCsrfToken::class,
        IlluminateRoutingMiddlewareSubstituteBindings::class,
    ],

    'api' => [
        EnsureFrontendRequestsAreStateful::class,
        IlluminateRoutingMiddlewareSubstituteBindings::class,
        'throttle:60,1',
    ],
];

Si usted tiene StartSession en tus api grupo de middleware, su configuración es incorrecta o innecesariamente complicada.

Aquí está mi trabajo ./config/auth.php archivo para su comparación:

'defaults' => [
    'guard' => 'web',
    'passwords' => 'users',
],

...

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'token',
        'provider' => 'users',
        'hash' => false,
    ],
],

Entonces, puede usar el guest middleware para rutas de inicio de sesión / registro y, lo que es más importante, debe declarar todos sus puntos finales que sirven JSON en api.php y usa el auth:sanctum middleware en esas rutas.

Una vez que crea que lo tiene funcionando, tengo dos pasos de prueba / depuración para usted:

Uno:

  • abrir Chrome> panel de herramientas de desarrollo
  • ir a la pestaña Aplicaciones
  • Verifique para asegurarse de que haya dos cookies: <app_name>_session, y XSRF-TOKEN
  • con la casilla de verificación recuérdame y remember: true en la carga útil de inicio de sesión, asegúrese de que haya una tercera cookie para remember_web_<hash>
  • asegúrese de que la cookie de sesión sea httpOnlyy asegúrese de que la cookie CSRF no lo esté (para que su JavaScript pueda acceder a ella)

Dos, en sus pruebas unitarias, asegúrese de que después $this->postJson(route('login'), $credentials), ves esto:

  • Auth::check() debería volver verdadero
  • Auth::user() debe devolver el objeto de usuario
  • Auth::logout() debe cerrar la sesión del usuario, e inmediatamente después de eso, $this->assertGuest('web'); debería volver verdadero

No se emocione demasiado hasta que haya verificado esos dos pasos, y emocione una vez que haya verificado esos pasos con éxito. Eso significará que está utilizando la lógica de autenticación predeterminada de Laravel.

Por si acaso, aquí hay un ejemplo de cómo adjuntar el token CSRF a través de JavaScript:

import Cookies from 'js-cookie';

axios.interceptors.request.use((request) => {
    try {
        const csrf = Cookies.get('XSRF-TOKEN');

        request.withCredentials = true;

        if (csrf) {
            request.headers.common['XSRF-TOKEN'] = csrf;
        }

        return request;
    } catch (err) {
        throw new Error(`axios# Problem with request during pre-flight phase: ${err}.`);
    }
});
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *