首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Next-Auth凭据提供程序具有Laravel -请求失败,状态代码为419

Next-Auth凭据提供程序具有Laravel -请求失败,状态代码为419
EN

Stack Overflow用户
提问于 2021-11-13 21:14:25
回答 3查看 2.9K关注 0票数 5

当我尝试使用Next-Auth的NextJS函数登录时,我有一个安装了Next-Auth的signIn前端和一个使用Sanctum的Laravel后端,它给了我这个错误:

代码语言:javascript
运行
复制
Request failed with status code 419

419与CSRF令牌有关,但在调用登录方法之前,我将通过调用密室/csrf-cookie路由来设置令牌。

...nextauth.js

代码语言:javascript
运行
复制
CredentialsProvider
        ({
            name: 'Email and Password',
            credentials: {
                email: {label: "Email", type: "email", placeholder: "Your Email"},
                password: {label: "Password", type: "Password"}
            },
            async authorize({email, password}, req) {
                await apiClient.get("/sanctum/csrf-cookie");
                const user = await apiClient.post('/customer/login', {
                    email: email,
                    password: password,
                });

                if (user) {
                    return user
                } else {
                    return null

                }
            }
        })

apiClient.js

代码语言:javascript
运行
复制
import axios from 'axios';

const apiClient = axios.create({
    baseURL: 'http://localhost:8000',
    withCredentials: true,
});

export default apiClient;

当我第一次尝试登录时,我被重定向到/api/auth/signIn?csrf=true,当我再次尝试登录时,我被重定向到/api/auth/error?error=Request failed with status code 419

我尝试使用来自客户端的API调用访问后端登录路由,它工作正常,没有任何故障。

为什么当从客户端调用时,请求在两个服务器之间运行良好,却失败了?我并不完全理解为什么下一个服务器不能向Laravel发送带有csrf头的请求。当涉及到服务器时,cookie不是通过第一次调用sanctum/cookie来设置的吗?CSRF不适用于两个服务器之间的对话吗?

我在这里错过了什么?任何帮助都将不胜感激。

在评论之后,我尝试显式地传递这个问题后面的cookies 为什么cookies不通过getServerSideProps ( Next.js )发送到服务器?,但是我仍然得到了一个CSRF令牌错配错误。

EN

回答 3

Stack Overflow用户

发布于 2022-07-06 00:25:13

几天后,我找到了一个对我有用的解决方案。

首先,我们需要理解...nextauth.js的代码是服务器端的,所以这是在Node.js中运行的,而不是在浏览器中运行,因此我们需要在服务器端执行的所有请求中手动设置cookie。

来自Laravel Sanctum文件:

如果您的JavaScript HTTP库没有为您设置值,则需要手动设置XSRF令牌头,以匹配此路由设置的XSRF-令牌cookie的值。

因此,我们需要手动将cookie添加到请求中。下面是代码:

...nexthauth.js

代码语言:javascript
运行
复制
import NextAuth from "next-auth"
import Credentials from 'next-auth/providers/credentials'
import axios from "../../../lib/axios";

//This is for getting the laravel-session cookie and the CSRF cookie 
//from any response of Sanctum or API Breeze
//In my case, the cookies returned are always two and I only need this, 
//so you can edit for get independent of position and cookies.
const getCookiesFromResponse = (res) => {
    let cookies = res.headers['set-cookie'][0].split(';')[0] + '; ' 
    cookies += res.headers['set-cookie'][1].split(';')[0] + '; '
    return cookies
}

//This is to get the X-XSRF-TOKEN from any response of Sanctum or API Breeze, 
//In my case, the token is always returned first, 
//so you can edit for get independent of position
const getXXsrfToken = (res) => {
    return decodeURIComponent(res.headers['set-cookie'][0].split(';')[0].replace('XSRF-TOKEN=',''))
}

//This method works to make any request to your Laravel API
//res_cookies are the cookies of the response of last request you do
//obviously res_cookies is null in your first request that is "/sanctum/csrf-cookie"
const makeRequest = async (method='get', url, dataForm = null, res_cookies ) => {
    const cookies = res_cookies != null ? getCookiesFromResponse(res_cookies) : null
    const res = await axios.request({
        method: method,
        url: url,
        data: dataForm,
        headers: {
            origin: process.env.NEXTAUTH_URL_INTERNAL, // this is your front-end URL, for example in local -> http://localhost:3000
            Cookie: cookies, // set cookie manually on server
            "X-XSRF-TOKEN": res_cookies ? getXXsrfToken(res_cookies) : null
        },
        withCredentials: true,
        credentials: true,
    })
    return res
}

const nextAuthOptions = (req, res) => {
    return {
        providers: [
            Credentials({
                name: 'Email and Password',
                credentials: {
                    email: { label: "Email", type: "email", placeholder: "Your Email" },
                    password: {  label: "Password", type: "password" }
                },
                async authorize(credentials) {
                    const csrf = await makeRequest('get', '/sanctum/csrf-cookie', null, null)
                    const user = await makeRequest('post', '/customer/login',  credentials, csrf )

                    if(user) return user
                    return null
                   
                }
            })
        ]
    }
}

lib/axos.js

代码语言:javascript
运行
复制
import Axios from 'axios'

const axios = Axios.create({
    baseURL: process.env.NEXT_PUBLIC_BACKEND_URL,
    headers: {
        'X-Requested-With': 'XMLHttpRequest',
    },
    withCredentials: true,
    credentials: true
})

export default axios

现在,如果您需要将cookie发送到前端(浏览器),您可以看到这个答案

票数 7
EN

Stack Overflow用户

发布于 2022-06-12 10:02:31

这是基于会话的交流。您应该首先从服务器获得一个CSRF令牌。

代码语言:javascript
运行
复制
const csrf = () => axios.get('/sanctum/csrf-cookie')

然后,在登录或注册之前,您必须这样做,然后尝试登录或注册。

代码语言:javascript
运行
复制
const login = async (email, pass) => {
    await csrf()
    axios
        .post('/login', {email: email, password: pass})
        .then(() => mutate())
        .catch(error => {
            if (error.response.status !== 422) throw error
        })
}
票数 -1
EN

Stack Overflow用户

发布于 2022-03-28 20:31:32

我有这个问题,花了几个小时才解决了这个问题,只是换了这句话:

代码语言:javascript
运行
复制
import axios from 'axios';

按照这一行:

代码语言:javascript
运行
复制
import axios from '@/lib/axios'
票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69958294

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档