如何使用Laravel和Nuxtjs进行身份验证,包括登录、注销和密码重置



我找不到任何资源来帮助解决这个问题,有一些repo提供了某种类型的基础,但实际上并不是很多。

目标:运行Laravel具有后端API,运行NuxtJS作为前端SPA,可以是两个单独的位置,也可以合并为一个位置。

需要在两个系统之间进行正确的身份验证,以便登录用户。Laravel Sanctum希望解决一些SPA问题,但很难找到真正显示完整设置示例的适当文档。

  1. 测试了这个想法https://github.com/zondycz/laravel-nuxt-sanctum但是已经失败,无法使用npm,必须使用yarn,但是,登录错误,无法开箱即用。回购需要工作。

  2. 本教程以Laravel为后端的Nuxt SPA中的安全身份验证非常深入,看起来很有前景,然而,刷新令牌似乎不适用于SPA方面,因为作者是在静态Nuxt上开发的。虽然我觉得它可以修改以发挥作用,但我还没有找到解决方案。

  3. 这个模板,Laranuxt看起来很有前途,虽然我还没有尝试过,但我不确定他们是否在这个时候定期更新它,它以前是由Laravel Nuxt JS(放弃的项目)构建的

我能够运行#2,虽然刷新令牌并不完全有效,但我仍然可以对用户进行身份验证,但现在的另一个问题是密码重置,我无法通过nuxt表单正确设置。

有人找到资源或通过这些框架之间的沟通解决了这个问题吗?还是我要做一个似乎看不到尽头的兔子洞?

我想另一种方式可能是说,你能做一个完全安静的身份验证系统吗?

希望这不是一个太宽泛的话题,寻找一些关于这个问题的指导,因为如果不自己写太多核心代码,很难找到合适的教程或文档。

在将前端和后端拆分到不同的域时,似乎许多人都很难实现Sanctum for SPA身份验证,而这个问题通常与CORS有关。Sanctum文档很棒,但假设了解CORS(或假设请求来源相同)。我会分解我所看到的设置,在我觉得文档不足的地方提供一点额外的支持。答案很长,但最后我将回答您的问题,该问题似乎特别关注身份验证。

摘自Sanctum文档:

首先,您应该配置您的SPA将从哪些发出请求

假设您的前端应用程序位于https://www.my-awesome-app.io,什么是?那么...怎么样http://localhost:3000?域映射到IP地址,而不是协议或端口号。因此,给定示例中的域为www.my-wesome-app.iolocalhost。考虑到这一点,在这个阶段,您需要做的就是转到配置目录中的sanctum.php文件,并设置'stateful'密钥的值,以匹配Laravel API将接收请求的域虽然域名的定义不包括端口号,但Sanctum文档明确表示,如果您通过需要特定端口的URL访问,这也是必需的。

/config/sanctum.php
...
'stateful' => [
'localhost:3000',
],

'stateful' => [
'my-awesome-app.io',
],

.env文件在这里很有用。

如果您在对在单独子域上执行的SPA中的应用程序进行身份验证时遇到问题,则可能是您的CORS(跨源资源共享)或会话cookie设置配置错误

的确如此。那么,正确的设置是什么样子的呢?假设最近的Laravel版本使用了fruitcake/Laravel-cors包,那么/config文件夹中就会有一个cors.php文件。默认值看起来像:

默认

/config/cors.php
...
'paths' => ['api/*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,

我们在这里有一些工作要做。首先,paths。目前,我们的Laravel API已设置为允许来自任何外部来源的请求,仅当他们试图访问/API/路由*时。根据Sanctum文档的要求,当我们尝试从路径/sanctum/csrf-cookie访问csrf cookie时,这可能会在早期导致问题。在我们的cors.php文件中不明确允许对该路径的请求,因此它们将失败。要修复,我们可以这样做:

'paths' => [
'api/*',
'sanctum/csrf-cookie'
]

现在,对/sancum/csrf-cookie的请求将被允许。顺便说一句,我个人发现将前缀从sanctum更改为api非常有用,这样我就可以为我的http客户端(通常是axios)设置一个基本url。

import axios from 'axios';
axios.defaults.withCredentials = true;
axios.defaults.baseURL = 'http://localhost:3000/api';

要更改路径,您可以在/config/asantum.php文件中更改以下内容:

'prefix' => 'api',

现在,对/api/csrf-cookie的GET请求将返回cookie,而不是/sancum/csrf-cookie。

接下来是allowed-origins。默认情况下,它被设置为*,这意味着";任何来源";。来源是向您的Laravel API发送请求的应用程序的协议、域和端口号。所以回到我们之前的例子,它们的起源是http://localhost:3000https://www.my-awesome-app.io。这些是您应该用于允许来自前端应用程序的请求的确切值:

'allowed_origins' => ['http://localhost:3000'],

我建议将其移到.env文件中,并为本地和生产创建一个单独的源。

/config/cors.php
...
'allowed_origins' => [env('ALLOWED_ORIGINS')],

/.env
...
ALLOWED_ORIGINS=http://localhost:3000

文档确实提到了我们的cors配置的最后一部分,即

'supports_credentials' => false,

必须更改为:

'supports_credentials' => true,

我们的/config/cors.php文件现在看起来像:

修改

/config/cors.php
...
'paths' => [
'api/*',
'sanctum/csrf-cookie'
],
'allowed_methods' => ['*'],
'allowed_origins' => [env('ALLOWED_ORIGINS')],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,

奖金信息,Chrome将不允许向返回标头的服务器发出认证请求Access-Control-Allow-Origin: *

谷歌浏览器:一个通配符'*';不能在';访问控制允许来源';凭证标志为真时的标头

所以你应该确保在你的cors配置中设置了一个特定的原点!

最后,您应该确保应用程序的会话cookie域配置支持根域的任何子域。您可以通过在域前面加一个前导来实现这一点。在您的会话配置文件中:

这并不复杂,但似乎会引起人们的注意,所以我想提到它

'domain' => '.my-awesome-app.io',

在本地,单独使用localhost即可:

'domain' => 'localhost',

假设您已经遵循了Sanctum文档中的其余说明(设置axios.defaults.withCredentials = true;、添加中间件等),那么您的后端配置现在就完成了。

前端和身份验证

我喜欢圣地,我非常感谢创作者;所以我这么说是出于尊重;在这一点上,文档缺乏一点深度。抓住csrf代币是非常直接的,然后。。。

一旦CSRF保护初始化,您应该向典型的Laravel/login路由发出POST请求。这个/登录路由可以由laravel/jetstream身份验证脚手架包提供。如果登录请求成功,您将通过身份验证,随后对API路由的请求将自动通过Laravel后端颁发给您的客户端的会话cookie进行身份验证

看来他们已经更新了文档在我写这篇文章的时候,我已经查看了最新的文档,现在它强调了一个事实,即您可以自由编写自己的登录端点。这种情况一直都是这样,但可能有一些人逃脱了,也许是按照上面的指示("你应该向典型的Laravel/login路由发出POST请求。")也可能不清楚你是否可以覆盖默认的Laravel方法,以防止默认身份验证设置的不必要的副作用,比如重定向到/home page等。

编写自己的登录控制器很简单,我更喜欢为Sanctum这样做。这里有一个你可以使用:

<?php
namespace AppHttpControllers;
use IlluminateHttpRequest;
use IlluminateSupportFacadesAuth;
use IlluminateValidationValidationException;
class LoginController extends Controller
{

public function login(Request $request)
{
$request->validate([
'email' => ['required', 'email'],
'password' => 'required'
]);
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
return response()->json(Auth::user(), 200);
}
throw ValidationException::withMessages([
'email' => 'The provided credentails are incorect.'
]);
}
}

请随意修改以满足您的需求。

如何在前端管理您的状态(例如,确保您的应用程序记住您已登录)也取决于您。有很多选择,但如果我们使用Sanctum,我认为我们应该专注于一种简单的基于cookie的方法。这是我使用的一个:

  1. 登录您的应用程序。一个身份验证会话建立,您的浏览器保存您的Laravel API提供的cookie
  2. 让您的登录脚本返回经过身份验证的用户(上面提供的脚本就是这样做的)。将该用户的详细信息保存到您的应用程序状态(例如Vuex)
  3. 随时检查您的状态是否包含用户,以确保对未经授权的用户采取行动。重定向到登录页面是身份验证检查失败

以上是使用中间件的Nuxt.js形式。

/middleware/auth-check.js
export default async function ({ store, redirect }) {
// Check if the user is not already in the store.
if (store.state.user === null) {
// Call your Laravel API to get the currently authenticated user.
// It doesn't matter if the store has been wiped out due to a page
// refresh- the browser still has the cookies, which will be sent
// along with this request.
try {
let rsp = await user.getAuthenticatedUser()
// If we get the user from the Laravel API, push it back in to
// the store and carry on to the page.
store.commit('SET_AUTH_USER', rsp.data)
} catch (e) {
// If our API doesn't return the user for any reason, redirect to
// the login page.
return redirect('/login')
}
}
// If not, carry on to the page.
}

/pages/admin.vue
export default {
middleware: auth-check
}

上面的代码只是为了举例,但它通常是我在Vue/Nuxt和Sanctum中使用的。

希望这能有所帮助,如果有人能从中受益,很乐意进一步阐述。

最新更新