当我尝试使用Next-Auth的NextJS函数登录时,我有一个安装了Next-Auth的signIn前端和一个使用Sanctum的Laravel后端,它给了我这个错误:
Request failed with status code 419
419与CSRF令牌有关,但在调用登录方法之前,我将通过调用密室/csrf-cookie路由来设置令牌。
...nextauth.js
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
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令牌错配错误。
发布于 2022-07-06 00:25:13
几天后,我找到了一个对我有用的解决方案。
首先,我们需要理解...nextauth.js的代码是服务器端的,所以这是在Node.js中运行的,而不是在浏览器中运行,因此我们需要在服务器端执行的所有请求中手动设置cookie。
如果您的JavaScript HTTP库没有为您设置值,则需要手动设置XSRF令牌头,以匹配此路由设置的XSRF-令牌cookie的值。
因此,我们需要手动将cookie添加到请求中。下面是代码:
...nexthauth.js
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
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发送到前端(浏览器),您可以看到这个答案。
发布于 2022-06-12 10:02:31
这是基于会话的交流。您应该首先从服务器获得一个CSRF令牌。
const csrf = () => axios.get('/sanctum/csrf-cookie')
然后,在登录或注册之前,您必须这样做,然后尝试登录或注册。
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
})
}
发布于 2022-03-28 20:31:32
我有这个问题,花了几个小时才解决了这个问题,只是换了这句话:
import axios from 'axios';
按照这一行:
import axios from '@/lib/axios'
https://stackoverflow.com/questions/69958294
复制相似问题