Laravel Sanctum 未认证

17

我在我的项目中使用Laravel Sanctum和Angular作为前端。在第二个API请求中得到了未认证的错误。请告诉我我哪里做错了。

前端 -> 127.0.0.1:4200

后端 -> localhost:8888

.env配置

SESSION_DOMAIN=localhost SANCTUM_STATEFUL_DOMAINS=127.0.0.1

在api.php文件的路由组中添加了中间件auth:sanctum

参考:https://prnt.sc/rm9ejy

13个回答

20

针对出现未认证错误的用户,请确保按照以下步骤进行操作:

  • 向 /sanctum/csrf-cookie 发送 GET 请求
  • 向 web 路由 /login 发送 POST 请求,以获得认证

完成这些步骤后,您将成功通过 auth:sanctum 中间件在 WEB 路由或需要 CRSF 令牌的任何资源路由中进行认证。

[为什么会起作用]
/sanctum/csrf-cookie 发送一个空请求可以让 Laravel 向您的浏览器发送新的 cookie 命令,从而设置一个新的 CRSF 令牌,该令牌可以在您的 cookies 中找到。Axios 和大多数库默认将此新令牌作为头部 X-CSRF-TOKEN 的一部分发送,对于常规 Ajax 请求,请在您的头部或表单 _token 中明确包含它们,否则您的 SPA 仍将遭遇419 (令牌过期) 错误。

其他需要注意的事项:

  1. 确保将 SESSION_DOMAIN 设置为 localhost
  2. SANCTUM_STATEFUL_DOMAIN 设置为您的子域名/SPA 和端口,例如 localhost:8000

对于原始问题,请确保维护相同的域。我的意思是同时使用 localhost。并设置 SANCTUM_STATEFUL_DOMAIN = localhost:4200

编辑:

还需要设置 SESSION_DRIVER。


6
我认为对/sanctum/csrf-cookie的请求需要是一个GET请求。 - Chris J

19
添加您的域名,例如我的API正在本地主机(localhost)的8000端口运行,我的客户端正在本地主机的3000端口运行,所以我的环境设置如下所示。
SANCTUM_STATEFUL_DOMAINS=localhost:8000,localhost:3000

此外,添加您的会话域

SESSION_DOMAIN=localhost

我使用自定义域名来调用后端和前端,例如(后端)api.devtest.test(前端)devtest.test。在SESSION_DOMAIN中应该写什么? - Shulz
1
@Shulz .devtest.test(注意开头的 .)-请参考https://laravel.com/docs/10.x/sanctum#cors-and-cookies。 - Dan

13

你检查过你的Kernel.php了吗? app/Http/Kernel.php

确保取消注释 \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,, 因为默认情况下它被注释掉了。

'api' => [
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

3
你说得对!你所建议的内容也已经写在文档中,可以在这里查看:https://laravel.com/docs/8.x/sanctum#sanctum-middleware - Fernando Torres

8

经历了两天的痛苦和绝望,我得出了结论:Bearer标记没有附加到请求中,这是由于我的.htaccess配置引起的。

如果你和我一样无法通过API令牌进行认证,请尝试在Laravel项目的public目录下的.htaccess文件中添加以下行:

RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

RewriteEngine On 指令之后。
注:感谢Laravel not detecting auth token sent in the header and JWT package

2
Sanctum不使用令牌进行有状态认证,它使用cookie。 - LDUBBS
2
痛苦和绝望,我知道你的感受! - Sharkfin
1
谢谢,伙计。上面的解决方案可行!我浪费了很多时间自己摸索。 - Albert George

5

根据您分享的截图,我看到您的域名为localhost而不是127.0.01,只需执行以下操作:

SANCTUM_STATEFUL_DOMAINS=localhost

5

如果您使用Laravel Homestead,请使用您实际的域名。

SANCTUM_STATEFUL_DOMAINS=homestead.test

1
当我在计算机的/etc/hosts文件下使用虚拟域名“app.test”时,这对我有效。 - OzzyTheGiant

4

您正在运行哪个版本?从 V2.4.0 开始,您需要指定端口:

SANCTUM_STATEFUL_DOMAINS=localhost:4200

查看此问题以获取更多信息。


3
如果您在进入生产环境时遇到问题和/或有多个子域并且使用了https,请不要忘记端口是443,而不是通常的80。

E.g.:

SANCTUM_STATEFUL_DOMAINS=*.example.com:443
SESSION_DOMAIN=.example.com

在失去了许多时间试图弄清楚为什么 Laravel、SPA 或 Android 应用程序轮流失败,但从未同时工作的日子里,终于找到了解决方案。

2

2
游戏结束了,但为了帮助那些一直在寻找解决方案的人,这里的大多数答案都有一些真相,只需要将它们结合起来使其正常工作:

  • ENV文件:SESSION_DOMAIN = localhost(或您的域名)
  • 在config->sanctum.php->stateful中(如果尚未存在):Sanctum :: currentApplicationUrlWithPort()
  • 在app / Http / Kernel.php API中添加作为第一个(这很重要):\ Laravel \ Sanctum \ Http \ Middleware \ EnsureFrontendRequestsAreStateful :: class,
  • 在app / http / kernel API中删除if there:\ Illuminate \ Session \ Middleware \ StartSession :: class,
  • 将auth:sanctum添加到您的api路由中间件中

还值得检查config->sanctum.php下的保护设置

就是这样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接