如果不用于令牌,Sanctum和Laravel的默认身份验证是否相同?

时间:2020-04-22 19:05:49

标签: laravel laravel-5 eloquent

我不太了解Laravel文档中的含义,所以我想确定一下。

我们的默认身份是一侧为Laravel,另一侧为Sanctum。

据说Sanctum可以执行令牌或仅实现身份验证。 :

对于此功能,Sanctum不使用任何类型的令牌。相反,Sanctum使用Laravel的内置基于cookie的会话身份验证服务。这提供了CSRF保护,会话身份验证以及防止通过XSS泄漏身份验证凭据的好处。只有当传入请求来自您自己的SPA前端(Vue.js)时,Sanctum才会尝试使用Cookie进行身份验证。

因此,如果从不使用令牌,那么Sanctum与默认的身份验证方法基本相同,对吗?基本上,它是否实现默认身份验证并在需要时添加令牌?如果是这样的话,圣所和护照有什么区别,因为他们做同样的事,但圣所据说是轻便的。这到底是什么意思?

感谢阅读

3 个答案:

答案 0 :(得分:8)

因此,如果从不使用令牌,那么Sanctum与默认的身份验证方法基本相同,对吗?

是的,它在后台使用laravel的默认身份验证。

看看圣所护卫队(以下代码来自github。它最后一次提交于4月11日,圣所2.x)

<?php

namespace Laravel\Sanctum;

use Illuminate\Contracts\Auth\Factory as AuthFactory;
use Illuminate\Http\Request;

class Guard
{
    /**
     * The authentication factory implementation.
     *
     * @var \Illuminate\Contracts\Auth\Factory
     */
    protected $auth;

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

    /**
     * Create a new guard instance.
     *
     * @param  \Illuminate\Contracts\Auth\Factory  $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  \Illuminate\Http\Request  $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)
        ));
    }
}

如果您选中_invoke()方法,则

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

使用以下身份找到经过身份验证的用户

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

在检查了Sanctum配置文件之后,当前没有sanctum.guard配置(这可能是将来的版本),因此默认情况下,Sanctum会使用web防护进行检查,因此基本上是相同的东西作为您的默认网络路由。

但是您误解了圣殿的使用。 Sanctum用于API身份验证,而不用于Web身份验证(尽管它也可以用于Web身份验证)。 Sanctum的非令牌身份验证使您的SPA能够使用与移动应用程序相同的API(使用令牌身份验证),而无需令牌,并提供csrf和基于会话的身份验证的好处。

为帮助您更好地理解,假设您已经建立了一个使用令牌的API(如果已经使用sanctum令牌的话,则会简化事情)进行身份验证。现在,您希望构建一个使用相同API的SPA(可以在laravel项目本身内部构建,或者在同一域或不同域中的单独项目中构建),但是由于这是您自己构建的,因此可信站点,因此您不希望它使用令牌,而是使用laravel基于会话的默认身份验证以及csrf保护,同时还使用相同的api路由。 SPA将通过ajax与服务器通信。您还希望确保仅允许您的SPA使用基于会话的身份验证,而不允许其他第三方站点使用它。

这就是Sanctum的来历。您只需要将Sanctum中间件添加到api的{​​{1}}路由组中

app/Http/Kernel.php

然后配置圣所以允许您的SPA的域并配置cors(请检查docs以了解如何执行此操作)。然后只需将use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful; 'api' => [ EnsureFrontendRequestsAreStateful::class, 'throttle:60,1', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 中间件添加到您的路由中,就可以完成服务器端设置。

现在,如果请求具有令牌或请求是有状态的(会话cookie),这些路由将对用户进行身份验证。

现在,您的SPA无需令牌即可与API通信。

要获得csrf保护,请先调用auth:sanctum请求,这将在cookie中设置csrf令牌,而axios会自动将其附加到后续请求中

csrf-cookie

圣所和护照有什么区别,因为他们做同样的事,但圣所据说很轻巧。

嗯,就像它说的那样,圣所是轻量级的。这是因为Passport提供了完整的Oauth功能,而Sanctum仅专注于创建和管理令牌。为了以简单的方式解释Oauth,您必须在不同的站点上看到过axios.get('/sanctum/csrf-cookie').then(response => { // Login... }) Sign in with GoogleSign in with Facebook,然后可以使用google / facebook / github将其签名到那些站点帐户。这是可能的,因为Google,Facebook和Github提供了Oauth功能(仅是一个简单的示例,不会涉及太多细节)。对于大多数网站,您实际上并不需要Passport,因为它提供了许多不需要的功能。对于简单的api身份验证,Sanctum绰绰有余

答案 1 :(得分:3)

注意::此答案适用于Laravel Sanctum +同域SPA

要添加到这些答案中,默认的Laravel身份验证使用web保护,因此您必须将其用于身份验证路由(对于同域SPA应用程序)。

例如,您可以创建指向Laravel的RegistersUsers特性和AuthenticatesUsers特性的自己的路线:

web.php

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

    Route::post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail');
    Route::post('password/reset', 'Auth\ResetPasswordController@reset');

    Route::post('email/verify/{user}', 'Auth\VerificationController@verify')->name('verification.verify');
    Route::post('email/resend', 'Auth\VerificationController@resend');

    Route::post('oauth/{driver}', 'Auth\OAuthController@redirectToProvider')->name('oauth.redirect');
    Route::get('oauth/{driver}/callback', 'Auth\OAuthController@handleProviderCallback')->name('oauth.callback');
});

Route::post('logout', 'Auth\LoginController@logout')->name('logout');

但是请确保它们位于web.php文件中。例如,如果它们在api.php文件中,我会看到一些关于session store not on request的奇怪错误,而RequestGuard::logout()不是一个函数。我相信这与auth特性中通过$this->guard()的默认身份验证保护有关,也与api.php的{​​{1}}前缀有关。

/api前缀似乎相关,因为如果您使用作曲者程序包Ziggy实现/apiroute('login'),它们实际上将解析为route('logout')/api/login

我怀疑这导致了圣所的问题。解决方法是确保路由在/api/logout中。如果某个人的配置相似,或者例如,如果他们在web.php中声明了Auth::routes(),则可能会重现此错误。

仔细检查您的 Kernel.php (应该是这样):

api.php

如果您的protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, // \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 'api' => [ EnsureFrontendRequestsAreStateful::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, 'throttle:60,1', ], ]; 中间件组中有StartSession,则说明您的配置不正确或不必要的盘绕。

这是我的工作 ./ config / auth.php 文件供您比较:

api

然后,您可以将'defaults' => [ 'guard' => 'web', 'passwords' => 'users', ], ... 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'token', 'provider' => 'users', 'hash' => false, ], ], 中间件用于登录/注册路由,非常重要的是,然后应在guest中声明所有JSON服务端点,并使用api.php中间件在那些路线上。

一旦您认为它可以正常工作,我将为您提供两个测试/调试步骤:

一个

  • 打开Chrome>“开发工具”窗格
  • 转到“应用程序”标签
  • 检查以确保有两个cookie:auth:sanctum<app_name>_session
  • 使用“记住我”复选框和登录有效载荷中的XSRF-TOKEN,确保为remember: true提供第三个cookie
  • 确保会话cookie是remember_web_<hash>,并确保CSRF cookie不是(以便您的JavaScript可以访问它)

两个,请在单元测试中确保在httpOnly之后看到以下内容:

  • $this->postJson(route('login'), $credentials)应该返回true
  • Auth::check()应该返回用户对象
  • Auth::user()应该注销用户,然后紧接着Auth::logout()应该返回true

在您确认这两个步骤之前,不要太兴奋,在成功验证这些步骤之后,请不要兴奋。这意味着您正在使用Laravel的默认身份验证逻辑。

出于良好的考虑,下面是通过JavaScript附加CSRF令牌的示例:

$this->assertGuest('web');

答案 2 :(得分:1)

Sanctum有两个单独的身份验证系统,有一个基于cookie的会话身份验证,该会话身份验证用于单页应用程序,在该应用程序中您将发送api请求(ajax,fetch等),而不是服务器端呈现(该请求在每次页面加载),sanctum可以使用此cookie(默认身份验证)而无需重新加载页面。

第二种身份验证系统是基于令牌的,旨在用于移动应用程序。