Pou*_*nte 12 laravel eloquent laravel-5
我不太确定 Laravel 文档中的含义,所以我要求确定。
我们一方面有 Laravel 的默认身份验证,另一方面有 Sanctum 的默认身份验证。
据说 Sanctum 既可以做代币,也可以简单地实现身份验证。:
对于此功能,Sanctum 不使用任何类型的令牌。相反,Sanctum 使用 Laravel 内置的基于 cookie 的会话身份验证服务。这提供了 CSRF 保护、会话身份验证以及防止身份验证凭据通过 XSS 泄漏的好处。当传入请求来自您自己的 SPA 前端 (Vue.js) 时,Sanctum 只会尝试使用 cookie 进行身份验证。
因此,如果从不使用令牌,Sanctum 与默认的身份验证方法基本相同,对吗?基本上,它是否实现了默认身份验证并在需要时添加令牌?如果是这样,sanctum 和护照有什么区别,因为它们做同样的事情,但据说 Sanctum 是轻量级的。这实际上意味着什么?
谢谢阅读
Aru*_*A S 12
因此,如果从不使用 Tokens,Sanctum 与默认的 Authentication 方法基本相同,对吗?
是的,在幕后它使用 laravel 的默认身份验证。
看一下 sanctum 守卫(下面的代码取自 github。最后一次提交是在 4 月 11 日,sanctum 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)
));
}
}
Run Code Online (Sandbox Code Playgroud)
如果你检查_invoke()方法,
if ($user = $this->auth->guard(config('sanctum.guard', 'web'))->user()) {
return $this->supportsTokens($user)
? $user->withAccessToken(new TransientToken)
: $user;
}
Run Code Online (Sandbox Code Playgroud)
使用身份验证的用户找到
$user = $this->auth->guard(config('sanctum.guard', 'web'))->user()
Run Code Online (Sandbox Code Playgroud)
在检查了 sanctum 配置文件后,目前没有sanctum.guard配置(它可能意味着未来的某个版本),所以web默认情况下sanctum 会检查守卫,所以它基本上和你的默认 web 路由做同样的事情。
但是你误解了 Sanctum 的用法。Sanctum 用于 API 身份验证而不是 Web 身份验证(尽管它也可以用于 Web 身份验证)。Sanctum 的非令牌身份验证使您的 SPA 能够使用与移动应用程序(使用令牌身份验证)相同的 API,而无需令牌并提供 csrf 和基于会话的身份验证的好处。
为了帮助您更好地理解,假设您已经构建了一个使用令牌进行身份验证的 API(如果它已经使用 sanctum 作为令牌,这会使事情变得更简单)。现在您希望构建一个使用相同 API 的 SPA(可以在 laravel 项目本身内部构建,也可以在同一个域或不同域上构建一个单独的项目),但是由于这将由您构建,因此它是一个受信任的站点,因此您不希望它使用令牌,而是使用 Laravel 基于默认会话的身份验证以及 csrf 保护,同时还使用相同的 api 路由。SPA 将通过 ajax 与服务器通信。您还希望确保只允许您的 SPA 使用基于会话的身份验证,而不允许其他第三方站点使用它。
所以这就是 Sanctum 的用武之地。您只需要将 Sanctum 中间件添加到您的api路由组中app/Http/Kernel.php
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
'api' => [
EnsureFrontendRequestsAreStateful::class,
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
Run Code Online (Sandbox Code Playgroud)
然后配置 sanctum 以允许您的 SPA 域并配置 cors(查看文档以了解如何执行此操作)。然后只需将auth:sanctum中间件添加到您的路由中,您就完成了服务器端设置。
现在,如果请求具有令牌或者它是有状态的(会话 cookie),这些路由将对用户进行身份验证。
现在您的 SPA 可以在没有令牌的情况下与您的 API 进行通信。
要获得 csrf 保护,请先调用csrf-cookie请求,这将在您的 cookie 中设置 csrf 令牌,axios 会自动将其附加到后续请求中
axios.get('/sanctum/csrf-cookie').then(response => {
// Login...
})
Run Code Online (Sandbox Code Playgroud)
sanctum 和护照有什么区别,因为它们做同样的事情,但据说 Sanctum 是轻量级的。
嗯,正如它所说的,sanctum 是轻量级的。这是因为 Passport 提供了完整的 Oauth 功能,而 Sanctum 只专注于创建和管理令牌。为了用简单的方式解释 Oauth,您必须在不同的站点上看到那些Sign in with Google, Sign in with Facebook,Sign in with Github然后您可以使用您的 google/facebook/github 帐户将其签名到这些站点。这是可能的,因为谷歌、Facebook 和 Github 都提供了 Oauth 功能(只是一个简单的例子,不详述)。对于大多数网站,您实际上并不需要 Passport,因为它提供了许多您不需要的功能。对于简单的 api 身份验证 Sanctum 绰绰有余
注意:此答案适用于 Laravel Sanctum + 同域 SPA
要添加到这些答案中,默认的 Laravel 身份验证使用web保护,因此您必须将其用于身份验证路由(对于同域 SPA 应用程序)。
例如,您可以创建自己的路由,指向 Laravel 的RegistersUserstrait 和AuthenticatesUserstrait:
网页.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');
Run Code Online (Sandbox Code Playgroud)
但请确保它们在web.php文件中。例如,如果它们在api.php文件中,我会看到一些关于session store not on request并且RequestGuard::logout()不是函数的奇怪错误。我相信这与$this->guard()auth 特征中的默认 auth guard via有关,并且与api.php的/api前缀有关。
的/api,因为如果你使用的作曲家包齐格实现前缀似乎相关route('login')和route('logout'),他们实际上决心/api/login和/api/logout。
我怀疑这导致了 Sanctum 的问题。解决方法是确保路由在web.php. 如果他们的配置相似,或者例如,如果他们Auth::routes()在api.php.
仔细检查您的Kernel.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',
],
];
Run Code Online (Sandbox Code Playgroud)
如果您StartSession在api中间件组中,则您的配置不正确或不必要地复杂。
这是我的工作./config/auth.php文件,供您比较:
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
...
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
Run Code Online (Sandbox Code Playgroud)
然后,您可以将guest中间件用于登录/注册路由,非常重要的是,您应该在其中声明所有 JSON 服务端点api.php并auth:sanctum在这些路由上使用中间件。
一旦您认为它可以正常工作,我会为您提供两个测试/调试步骤:
一:
<app_name>_session, 和XSRF-TOKENremember: true登录有效负载,确保有第三个 cookieremember_web_<hash>httpOnly,并确保 CSRF cookie 不是(以便您的 JavaScript 可以访问它)二、在您的单元测试中,确保在 之后$this->postJson(route('login'), $credentials),您会看到:
Auth::check() 应该返回真Auth::user() 应该返回用户对象Auth::logout()应该将用户注销,然后立即$this->assertGuest('web');返回 true在您验证这两个步骤之前不要太兴奋,一旦您成功验证了这些步骤,请不要太兴奋。这意味着您正在使用 Laravel 的默认身份验证逻辑。
为了更好地衡量,以下是通过 JavaScript 附加 CSRF 令牌的示例:
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}.`);
}
});
Run Code Online (Sandbox Code Playgroud)