Защищенные маршруты с использованием JWT-токенов в NextJS + Django
Я начинаю новое приложение NextJS, в котором я использую Django в качестве API.
Я использую JWT-токены для аутентификации/авторизации и хотел создать защищенные маршруты. После изучения кучи руководств, видео и других вещей в Интернете, вот что я придумал:
Я создал экземпляр axios (api.js) (где я пытался перехватить запросы для установки заголовка Authorization):
import axios from "axios";
import Cookies from "js-cookie";
const api = axios.create({
baseURL: "http://127.0.0.1:8000/api/",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
});
api.interceptors.request.use((request) => {
const token = Cookies.get("accessToken");
if (token) {
api.defaults.headers.Authorization = `Bearer ${token.access}`;
}
return request;
});
export default api;
И AuthService.js (где я устанавливаю cookie при входе в систему):
import Cookies from "js-cookie";
import api from "./api";
export const AuthService = {
login: async (email, password) => {
const { data: token } = await api.post("token/", { email, password });
console.log(token);
if (token) {
console.log("Got token");
Cookies.set("accessToken", token.access, { expires: 60 });
api.defaults.headers.Authorization = `Bearer ${token.access}`;
const { data: user } = await api.get("users/current/");
console.log("Got user", user);
return user;
}
},
logout: async () => {
Cookies.remove("accessToken");
delete api.defaults.headers.Authorization;
},
getUser: async () => {
try {
const { data: user } = await api.get("users/current/");
return user;
} catch (error) {
console.log("Error", error);
}
},
};
Затем, в моем AuthContext у меня есть функция более высокого порядка (requireAuthentication), которая принимает другую функцию (в моем случае getServerSideProps) и перенаправляет на страницу входа, если токен доступа не установлен или является недействительным:
const AuthContext = createContext({});
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const login = async (email, password) => {
...
};
const logout = () => {
...
};
const getUser = async () => {
...
};
const contextValues = {
...
};
return (
<AuthContext.Provider value={contextValues}>
{children}
</AuthContext.Provider>
);
}
export default AuthContext;
export function requireAuthentication(gssp) {
return async (context) => {
const { req } = context;
if (req.cookies) {
const accessToken = req.cookies["accessToken"];
try {
const user = await AuthService.getUser();
console.log("user", user);
if (!accessToken || !user || !user.email) {
return {
redirect: {
permanent: false,
destination: "/login",
},
};
}
} catch (error) {
return {
redirect: {
permanent: false,
destination: "/login",
},
};
}
}
return gssp(context);
};
}
Затем я могу использовать эту функцию высшего порядка для компонентов, которые мне нужно "защитить", следующим образом:
import { requireAuthentication } from "../../contexts/AuthContext";
export default function Dashboard({ props }) {
return (
<div>
<h1>Dashboard</h1>
</div>
);
}
export const getServerSideProps = requireAuthentication((context) => {
// normal `getServerSideProps` code here
return {
props: {}, // will be passed to the page component as props
};
});
Кажется, я знаю, почему это не работает - когда я перехватываю запросы, куки не определяются, потому что я использую getServerSideProps, а куки находятся на стороне клиента.
Из того, что я прочитал, я могу использовать куки httponly, чтобы эта стратегия работала, но я не знаю как.
Является ли подход, который я использую, обычным/хорошим? Может ли кто-нибудь помочь мне с httponly cookie, если это решит мою проблему?
Пожалуйста, дайте мне знать, если у вас есть предложения и советы о том, как иметь "защищенные маршруты" с использованием JWT-токенов.
Спасибо.