Мой REST API возвращает accessToken и обновитьToken через файлы cookie только по протоколу HTTP, и каждый последующий запрос от внешнего интерфейса использует эти файлы cookie для аутентификации на внутреннем интерфейсе, например: В моем интерфейсе я использую перехватчики axios для автоматической обработки обновления accessToken. при необходимости или для входа в систему, если RefreshToken отсутствует, например:
введите здесь описание изображения
Код: Выделить всё
//axiosPrivate.js
import axios from 'axios';
const axiosPrivate = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_BEDAPP2,
withCredentials: true,
});
axiosPrivate.interceptors.request.use(
async (config) => {
config.timeout = 5000;
return config;
}, (error) => Promise.reject(error)
);
axiosPrivate.interceptors.response.use(
response => response,
async (error) => {
const prevRequest = error?.config;
if (error.response?.status === 401 &&
(error.response.data?.code === 'AccessTokenExpired' || error.response.data?.code === 'AccessTokenNotFound')
) {
try {
const response = await axios.get(process.env.NEXT_PUBLIC_API_BEDAPP2 + '/auth/refresh-token', { withCredentials: true });
return axiosPrivate(prevRequest);
} catch (error) {
try {
const response = await axios.post(process.env.NEXT_PUBLIC_API_BEDAPP2 + '/auth/login',
{
name: process.env.NEXT_PUBLIC_API_USERNAME,
password: process.env.NEXT_PUBLIC_API_PASSWORD
},
{ withCredentials: true });
return axiosPrivate(prevRequest);
} catch (error) {
return Promise.reject(error);
}
}
}
return Promise.reject(error);
}
);
export default axiosPrivate;
In my client component I import the axiosPrivate and I make the call to my restAPI, like this:
import { useEffect, useState } from "react";
import Loading from "../../../components/Loading";
import MessageError from "../../../components/MessageError";
import Modal from '../../../components/Modal';
import BedappMail from "../../../components/BedappMail";
import axiosPrivate from "../../../lib/axiosPrivate";
export default function Access() {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState('');
const [showModal, setShowModal] = useState(false);
const [email, setEmail] = useState();
const [data, setData] = useState([]);
const fetchData = async () => {
setIsLoading(true);
setError('');
try {
const { data } = await axiosPrivate.get('/users/usersaccess');
setData(data);
} catch (e) {
if (e.response) {
setError(e.response.data.message);
} else if (e.request) {
setError(e.request);
} else {
setError(e.message);
}
}
setIsLoading(false);
}
...
Чтобы решить эту проблему, я попытался выполнить эту часть аутентификации на стороне сервера, вот так:
Код: Выделить всё
//apiRequest.js
'use server';
import axios from 'axios';
const axiosPrivate = axios.create({
baseURL: process.env.API_BEDAPP2,
withCredentials: true,
});
axiosPrivate.interceptors.request.use(
async (config) => {
config.timeout = 5000;
return config;
}, (error) => Promise.reject(error)
);
axiosPrivate.interceptors.response.use(
response => response,
async (error) => {
const prevRequest = error?.config;
if (error.response?.status === 401 &&
(error.response.data?.code === 'AccessTokenExpired' || error.response.data?.code === 'AccessTokenNotFound')
) {
try {
const response = await axios.get(process.env.API_BEDAPP2 + '/auth/refresh-token', { withCredentials: true });
return axiosPrivate(prevRequest);
} catch (error) {
try {
const response = await axios.post(process.env.API_BEDAPP2 + '/auth/login',
{
name: process.env.API_USERNAME,
password: process.env.API_PASSWORD
},
{ withCredentials: true });
return axiosPrivate(prevRequest);
} catch (error) {
return Promise.reject(error);
}
}
}
return Promise.reject(error);
}
);
export const getRequest = async (url) => {
try {
const response = await axiosPrivate.get(url);
return { data: response.data };
} catch (e) {
if (e.response) {
throw new Error(e.response.data.message);
} else if (e.request) {
throw new Error(e.request);
} else {
throw new Error(e.message);
}
}
};
-------------------------------------------------------------------------------
//client component
import { useEffect, useState } from "react";
import Loading from "../../../components/Loading";
import MessageError from "../../../components/MessageError";
import Modal from '../../../components/Modal';
import BedappMail from "../../../components/BedappMail";
import getRequest from "../../../lib/apiRequest";
export default function Access() {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState('');
const [showModal, setShowModal] = useState(false);
const [email, setEmail] = useState();
const [data, setData] = useState([]);
const fetchData = async () => {
setIsLoading(true);
setError('');
try {
const { data } = await getRequest('/users/usersaccess');
setData(data);
} catch (e) {
if (e.response) {
setError(e.response.data.message);
} else if (e.request) {
setError(e.request);
} else {
setError(e.message);
}
}
setIsLoading(false);
}
...
Я не совсем понял, почему эти файлы cookie не передаются в браузер, но я решил переписать их вручную на стороне сервера, вот так (шрифт: Как пересылать файлы cookie между клиентом и сервером с помощью Действия сервера NextJS):
Код: Выделить всё
'use server';
import axios from 'axios';
import setCookieParser from 'set-cookie-parser';
import { cookies } from 'next/headers';
const proxyServerCookies = (cookieNames, response) => {
if (response.headers.has('set-cookie')) {
const cookieString = response.headers.get('set-cookie');
const cookieObject = setCookieParser.parse(setCookieParser.splitCookiesString(cookieString), {
map: true,
});
cookieNames.forEach((cookieName) => {
if (cookieObject[cookieName]) {
const cookie = cookieObject[cookieName];
cookies().set(cookieName, cookie.value, {
path: cookie.path,
domain: cookie.domain,
maxAge: cookie.maxAge,
sameSite: (cookie.sameSite),
expires: cookie.expires,
secure: cookie.secure,
httpOnly: cookie.httpOnly,
});
}
});
}
return response;
}
const axiosPrivate = axios.create({
baseURL: process.env.API_BEDAPP2,
withCredentials: true,
});
axiosPrivate.interceptors.request.use(
async (config) => {
const cookieStore = await cookies();
console.log(cookieStore.get('accessToken'));
config.timeout = 5000;
return config;
}, (error) => Promise.reject(error)
);
axiosPrivate.interceptors.response.use(
response => response,
async (error) => {
const prevRequest = error?.config;
if (error.response?.status === 401 &&
(error.response.data?.code === 'AccessTokenExpired' || error.response.data?.code === 'AccessTokenNotFound') &&
(!prevRequest.sent)
) {
prevRequest.sent = true;
try {
const response = await axios.get(process.env.API_BEDAPP2 + '/auth/refresh-token', { withCredentials: true });
await proxyServerCookies(['accessToken', 'refreshToken'], response);
return axiosPrivate(prevRequest);
} catch (error) {
try {
const response = await axios.post(process.env.API_BEDAPP2 + '/auth/login',
{
name: process.env.API_USERNAME,
password: process.env.API_PASSWORD
},
{ withCredentials: true });
await proxyServerCookies(['accessToken', 'refreshToken'], response);
return axiosPrivate(prevRequest);
} catch (error) {
return Promise.reject(error);
}
}
}
return Promise.reject(error);
}
);
export const getRequest = async (url) => {
try {
const response = await axiosPrivate.get(url);
return { data: response.data };
} catch (e) {
if (e.response) {
throw new Error(e.response.data.message);
} else if (e.request) {
throw new Error(e.request);
} else {
throw new Error(e.message);
}
}
};
Может ли кто-нибудь мне помочь?
Подробнее здесь: https://stackoverflow.com/questions/793 ... on-cookies
Мобильная версия