我有一个 Nuxt 应用程序作为客户端和一个 laravel 9 API,该 api 使用 Laravel-Sanctum,我在将 Nuxt 应用程序与 Laravel 连接时遇到问题,因为管理 sainttum 的端点告诉我我没有获得授权,无论是前面还是和后域不同,是否有我跳过的配置,这就是它不起作用的原因?在这里我与您分享我的代码:
配置/cors.php
<?php
return [
'paths' => ['api/*', 'login', 'logout', 'sanctum/csrf-cookie', 'api'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
];
配置/sanctum.php
<?php
use Laravel\Sanctum\Sanctum;
return [
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1,https://mango-grass-0b3b8cd10.3.azurestaticapps.net/',
Sanctum::currentApplicationUrlWithPort()
))),
// 'guard' => ['web'],
'expiration' => null,
'middleware' => [
'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
],
];
配置/session.php
<?php
use Illuminate\Support\Str;
return [
'driver' => env('SESSION_DRIVER', 'file'),
'lifetime' => env('SESSION_LIFETIME', 120),
'expire_on_close' => false,
'encrypt' => false,
'files' => storage_path('framework/sessions'),
'connection' => env('SESSION_CONNECTION'),
'table' => 'sessions',
'store' => env('SESSION_STORE'),
'lottery' => [2, 100],
'cookie' => env(
'SESSION_COOKIE',
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
),
'path' => '/',
'domain' => env('SESSION_DOMAIN'),
'secure' => env('SESSION_SECURE_COOKIE'),
'http_only' => true,
'same_site' => 'lax',
];
配置/kernel.php
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
class Kernel extends HttpKernel
{
protected $middleware = [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\Fruitcake\Cors\HandleCors::class,
];
protected $middlewareGroups = [
'web' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
// \Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Fruitcake\Cors\HandleCors::class,
],
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:60,1',
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Fruitcake\Cors\HandleCors::class,
],
];
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \App\Http\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
}
nuxt.config.js
auth: {
redirect: {
home: '/',
logout: '/login',
login: '/login',
},
plugins: [
'~/plugins/auth.js',
{ src: '~/plugins/sweetalert2.js', mode: 'client' },
{ src: '~/plugins/VueDebounce.js' },
],
strategies: {
laravelSanctum: {
provider: 'laravel/sanctum',
url: backendUrl,
endpoints: {
login: {
url: '/api/login',
},
logout: {
url: '/api/logout',
},
},
},
},
},
登录.vue
const handleSubmit = async () => {
if (email.value === '' || password === '') {
Swal.fire({
title: '¡Información!',
text: '¡Existen campos obligatorios vacíos.!',
icon: 'info',
confirmButtonText: 'Aceptar',
})
} else {
loaderButton.value = true
await $auth
.loginWith('laravelSanctum', {
data: { email: email.value, password: password.value },
})
.then((response) => {
backendService.value.getMe().then((responseMe) => {
localStorage.setItem('UserName', responseMe.name)
localStorage.setItem('UserEmail', responseMe.email)
localStorage.setItem('token', response.data.token)
getPermissionRol(responseMe.permission)
router.push('/')
})
})
.catch((error) => {
if (error.code === 'ECONNREFUSED') {
Swal.fire({
title: '¡Error!',
text: 'No se puede conectar con el servidor. Verifique su conexión a internet o inténtelo más tarde.',
icon: 'error',
confirmButtonText: 'Aceptar',
})
} else if (error.request && error.request.message) {
Swal.fire({
title: '¡Error!',
text: error.request.message,
icon: 'error',
confirmButtonText: 'Aceptar',
})
} else {
Swal.fire({
title: '¡Error!',
text: '¡Error!',
icon: 'error',
confirmButtonText: 'Aceptar',
})
}
})
.finally(() => {
loaderButton.value = false
})
}
非常感谢您的帮助。
我遵循了有关 sainttum 配置的文档中的步骤,我尝试将值放入 .env 文件中,但它也不起作用,当我尝试登录时,它不断向我发送错误“419 未知状态”。
设置 sainttumn.php :
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8080,::1',
Sanctum::currentApplicationUrlWithPort()
))),
然后在 .env 文件中设置 env 变量,如下所示:
FRONTEND_URL=http://localhost:3000
ROOT_URL=//127.0.0.1:8080
APP_URL=http://localhost
SESSION_DRIVER=cookie
SESSION_DOMAIN=.localhost
然后在 laravel 项目中运行这些命令:
php artisan config:clear && php artisan cache:clear && php artisan optimize && php artisan serve
然后在你的 nuxt login.vue 中:
async function validate() {
await useFetch("http://localhost:8080/sanctum/csrf-cookie", {
credentials: "include",
});
const token = useCookie('XSRF-TOKEN');
await useFetch("http://localhost:8080/api/login", {
credentials: "include",
method: "POST",
body: {
'email': 'email',
'password': 'password'
},
headers: {
'X-XSRF-TOKEN': token.value as string,
},
watch: false
})
// remaining codes...
}