使用下一个身份验证凭据提供程序时如何发送 httponly cookie 客户端? [英] How to send httponly cookies client side when using next-auth credentials provider?
问题描述
我正在创建一个下一个 js 应用程序,使用 next-auth 来处理身份验证.
我有一个外部后端 api,所以我正在使用凭据提供程序.
问题是后端发送 httponly cookie,但是当我在客户端发出请求时,这些cookie没有附加到浏览器.
在/pages/api/[...auth].js 中
import NextAuth from 'next-auth';从 'next-auth/providers' 导入提供者;从'../../../config/configAxios'导入clientAxios导出默认 NextAuth({提供者:[Providers.Credentials({异步授权(凭据){尝试 {const login = await clientAxios.post('/api/login', {用户名:凭据.用户名,密码:凭据.密码,is_master:凭证.is_master})const info = login.data.data.user常量令牌 = {accessToken: login.data.data.access_token,expiresIn: login.data.data.expires_in,refreshToken:login.data.data.refresh_token}//我可以在这里看到 cookieconst cookies = login.headers['set-cookie']返回 { 信息、令牌、cookie }} 捕捉(错误){控制台日志(错误)抛出(错误(error.response.data.M))}}})],回调:{async jwt(token, user, account, profile, isNewUser) {如果(令牌){//这里设置了cookie,但只在服务器端clientAxios.defaults.headers.common['Cookie'] = token.cookies}如果(用户){令牌 = {用户:用户信息,...用户令牌,}}返回令牌},异步会话(会话,令牌){//向会话添加属性,例如来自提供者的 access_token.session.user = token.usersession.accessToken = token.accessTokensession.refreshToken = token.refreshToken返回会话}},会议: {jwt: 真}})
我的 axios 配置文件
import axios from 'axios';常量 clientAxios = axios.create({baseURL:process.env.backendURL,withCredentials:真,标题:{'接受' : '应用程序/json',内容类型":应用程序/json"}});导出默认客户端Axios;
一个页面组件
import { getSession } from "next-auth/client";从../../../config/configAxios"导入clientAxios;从反应"导入 { useEffect }导出默认功能 PageOne (props) {使用效果(异步()=>;{//这个请求失败,cookies没有发送常量响应 = 等待 clientAxios.get('/api/info');}, [])返回 (<h1>你好世界!</h1></div>)}导出异步函数 getServerSideProps (context) {常量会话 = 等待 getSession(上下文)如果(!会话){返回 {重定向:{目的地:'/登录',永久:假}}}//这个请求有效常量响应 = 等待 clientAxios.get('/api/info');返回 {道具: {会议,信息:response.data}}} 解决方案 经过一段时间的研究,我想通了.
我必须在导出 NextAuth 的方式中更改/pages/api/auth.
代替
导出默认 NextAuth({提供者:[...]})
像这样导出它,这样我们就可以访问请求和响应对象了
export default (req, res) =>{返回 NextAuth(req, res, options)}
但要在选项对象中访问它们,我们可以将其设为回调
const nextAuthOptions = (req, res) =>{返回 {提供者:[...]}}导出默认值 (req, res) =>{返回 NextAuth(req, res, nextAuthOptions(req, res))}
要将 cookie 从后端发送回前端,我们必须在响应中添加一个Set-Cookie"标头
res.setHeader('Set-Cookie', ['cookie_name=cookie_value'])
完整的代码是
import NextAuth from 'next-auth';从 'next-auth/providers/credentials' 导入 CredentialsProvider;const nextAuthOptions = (req, res) =>{返回 {提供者:[凭据提供程序({异步授权(凭据){尝试 {const response = await axios.post('/api/login', {用户名:凭据.用户名,密码:凭据.密码})const cookies = response.headers['set-cookie']res.setHeader('Set-Cookie', cookies)返回响应数据} 捕捉(错误){控制台日志(错误)抛出(错误(error.response))}}})]}}导出默认值 (req, res) =>{返回 NextAuth(req, res, nextAuthOptions(req, res))}
I'm creating a next js application, using next-auth to handle authentication.
I have an external backend api, so I'm using Credentials Provider.
The problem is that the backend sends httponly cookies, but those are not being attached to the browser when i make a request client side.
In /pages/api/[...auth].js
import NextAuth from 'next-auth';
import Providers from 'next-auth/providers';
import clientAxios from '../../../config/configAxios'
export default NextAuth({
providers: [
Providers.Credentials({
async authorize(credentials) {
try {
const login = await clientAxios.post('/api/login', {
username: credentials.username,
password: credentials.password,
is_master: credentials.is_master
})
const info = login.data.data.user
const token = {
accessToken: login.data.data.access_token,
expiresIn: login.data.data.expires_in,
refreshToken: login.data.data.refresh_token
}
// I can see cookies here
const cookies = login.headers['set-cookie']
return { info, token, cookies }
} catch (error) {
console.log(error)
throw (Error(error.response.data.M))
}
}
})
],
callbacks: {
async jwt(token, user, account, profile, isNewUser) {
if (token) {
// Here cookies are set but only in server side
clientAxios.defaults.headers.common['Cookie'] = token.cookies
}
if (user) {
token = {
user: user.info,
...user.token,
}
}
return token
},
async session(session, token) {
// Add property to session, like an access_token from a provider.
session.user = token.user
session.accessToken = token.accessToken
session.refreshToken = token.refreshToken
return session
}
},
session: {
jwt: true
}
})
my axios config file
import axios from 'axios';
const clientAxios = axios.create({
baseURL: process.env.backendURL,
withCredentials: true,
headers:{
'Accept' : 'application/json',
'Content-Type' : 'application/json'
}
});
export default clientAxios;
a page component
import { getSession } from "next-auth/client";
import clientAxios from "../../../config/configAxios";
import { useEffect } from "react"
export default function PageOne (props) {
useEffect(async () => {
// This request fails, cookies are not sent
const response = await clientAxios.get('/api/info');
}, [])
return (
<div>
<h1>Hello World!</h1>
</div>
)
}
export async function getServerSideProps (context) {
const session = await getSession(context)
if (!session) {
return {
redirect: {
destination: '/login',
permanent: false
}
}
}
// This request works
const response = await clientAxios.get('/api/info');
return {
props: {
session,
info: response.data
}
}
}
解决方案 After time of researching I have figured it out.
I had to make a change in /pages/api/auth in the way I'm exporting NextAuth.
Instead of
export default NextAuth({
providers: [
...
]
})
Export it like this, so we can have access to request and response object
export default (req, res) => {
return NextAuth(req, res, options)
}
But to access them in the options object, we can make it a callback
const nextAuthOptions = (req, res) => {
return {
providers: [
...
]
}
}
export default (req, res) => {
return NextAuth(req, res, nextAuthOptions(req, res))
}
To send a cookie back to the frontend from the backed we must add a 'Set-Cookie' header in the respond
res.setHeader('Set-Cookie', ['cookie_name=cookie_value'])
The complete code would be
import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
const nextAuthOptions = (req, res) => {
return {
providers: [
CredentialsProvider({
async authorize(credentials) {
try {
const response = await axios.post('/api/login', {
username: credentials.username,
password: credentials.password
})
const cookies = response.headers['set-cookie']
res.setHeader('Set-Cookie', cookies)
return response.data
} catch (error) {
console.log(error)
throw (Error(error.response))
}
}
})
]
}
}
export default (req, res) => {
return NextAuth(req, res, nextAuthOptions(req, res))
}
这篇关于使用下一个身份验证凭据提供程序时如何发送 httponly cookie 客户端?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文