last changes
This commit is contained in:
182
src/providers/authProvider.ts
Normal file
182
src/providers/authProvider.ts
Normal file
@ -0,0 +1,182 @@
|
||||
import type { AuthProvider } from "@refinedev/core";
|
||||
import axios, { AxiosError } from "axios";
|
||||
|
||||
import { jwtDecode } from "jwt-decode";
|
||||
|
||||
export const TOKEN_KEY = "refine-auth";
|
||||
|
||||
interface AuthResponse {
|
||||
token: string;
|
||||
user: {
|
||||
id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
is_admin: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface ErrorResponse {
|
||||
message: string;
|
||||
}
|
||||
|
||||
class AuthError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "AuthError";
|
||||
}
|
||||
}
|
||||
|
||||
interface JWTPayload {
|
||||
user_id: number;
|
||||
email: string;
|
||||
is_admin: boolean;
|
||||
exp: number;
|
||||
}
|
||||
|
||||
export const authProvider: AuthProvider = {
|
||||
login: async ({ email, password }) => {
|
||||
try {
|
||||
const response = await axios.post<AuthResponse>(
|
||||
`${import.meta.env.VITE_KRBL_API}/auth/login`,
|
||||
{
|
||||
email,
|
||||
password,
|
||||
}
|
||||
);
|
||||
|
||||
const { token, user } = response.data;
|
||||
|
||||
if (token) {
|
||||
localStorage.setItem(TOKEN_KEY, token);
|
||||
localStorage.setItem("user", JSON.stringify(user));
|
||||
|
||||
return {
|
||||
success: true,
|
||||
redirectTo: "/",
|
||||
};
|
||||
}
|
||||
|
||||
throw new AuthError("Неверный email или пароль");
|
||||
} catch (error) {
|
||||
const errorMessage =
|
||||
(error as AxiosError<ErrorResponse>)?.response?.data?.message ||
|
||||
"Неверный email или пароль";
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: new AuthError(errorMessage),
|
||||
};
|
||||
}
|
||||
},
|
||||
logout: async () => {
|
||||
try {
|
||||
await axios.post(
|
||||
`${import.meta.env.VITE_KRBL_API}/auth/logout`,
|
||||
{},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem(TOKEN_KEY)}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Ошибка при выходе:", error);
|
||||
}
|
||||
|
||||
localStorage.removeItem(TOKEN_KEY);
|
||||
localStorage.removeItem("user");
|
||||
return {
|
||||
success: true,
|
||||
redirectTo: "/login",
|
||||
};
|
||||
},
|
||||
check: async () => {
|
||||
const token = localStorage.getItem(TOKEN_KEY);
|
||||
if (!token) {
|
||||
return {
|
||||
authenticated: false,
|
||||
redirectTo: "/login",
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${import.meta.env.VITE_KRBL_API}/auth/me`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (response.status === 200) {
|
||||
// Обновляем информацию о пользователе
|
||||
localStorage.setItem("user", JSON.stringify(response.data));
|
||||
return {
|
||||
authenticated: true,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
localStorage.removeItem(TOKEN_KEY);
|
||||
localStorage.removeItem("user");
|
||||
return {
|
||||
authenticated: false,
|
||||
redirectTo: "/login",
|
||||
error: new AuthError("Сессия истекла, пожалуйста, войдите снова"),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
authenticated: false,
|
||||
redirectTo: "/login",
|
||||
};
|
||||
},
|
||||
getPermissions: async () => {
|
||||
const token = localStorage.getItem(TOKEN_KEY);
|
||||
if (!token) return null;
|
||||
|
||||
try {
|
||||
const decoded = jwtDecode<JWTPayload>(token);
|
||||
if (decoded.is_admin) {
|
||||
document.body.classList.add("is-admin");
|
||||
} else {
|
||||
document.body.classList.remove("is-admin");
|
||||
}
|
||||
return decoded.is_admin ? ["admin"] : ["user"];
|
||||
} catch {
|
||||
document.body.classList.remove("is-admin");
|
||||
return ["user"];
|
||||
}
|
||||
},
|
||||
getIdentity: async () => {
|
||||
const token = localStorage.getItem(TOKEN_KEY);
|
||||
const user = localStorage.getItem("user");
|
||||
|
||||
if (!token || !user) return null;
|
||||
|
||||
try {
|
||||
const decoded = jwtDecode<JWTPayload>(token);
|
||||
const userData = JSON.parse(user);
|
||||
|
||||
return {
|
||||
...userData,
|
||||
is_admin: decoded.is_admin, // всегда используем значение из токена
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onError: async (error) => {
|
||||
const status = (error as AxiosError)?.response?.status;
|
||||
if (status === 401 || status === 403) {
|
||||
localStorage.removeItem(TOKEN_KEY);
|
||||
localStorage.removeItem("user");
|
||||
return {
|
||||
logout: true,
|
||||
redirectTo: "/login",
|
||||
error: new AuthError("Сессия истекла, пожалуйста, войдите снова"),
|
||||
};
|
||||
}
|
||||
return { error };
|
||||
},
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
import dataProvider from "@refinedev/simple-rest";
|
||||
|
||||
import { TOKEN_KEY } from "../authProvider";
|
||||
import { TOKEN_KEY } from "@providers";
|
||||
|
||||
import axios from "axios";
|
||||
import { languageStore } from "../store/LanguageStore";
|
||||
|
24
src/providers/i18nProvider.ts
Normal file
24
src/providers/i18nProvider.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import i18n from 'i18next'
|
||||
import {initReactI18next} from 'react-i18next'
|
||||
import {I18nProvider} from '@refinedev/core'
|
||||
|
||||
import translationRU from '../locales/ru/translation.json'
|
||||
|
||||
i18n.use(initReactI18next).init({
|
||||
resources: {
|
||||
ru: {
|
||||
translation: translationRU,
|
||||
},
|
||||
},
|
||||
lng: 'ru',
|
||||
fallbackLng: 'ru',
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
})
|
||||
|
||||
export const i18nProvider: I18nProvider = {
|
||||
translate: (key, options) => i18n.t(key, options) as string,
|
||||
changeLocale: (locale: string) => i18n.changeLanguage(locale),
|
||||
getLocale: () => i18n.language,
|
||||
}
|
3
src/providers/index.ts
Normal file
3
src/providers/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './data'
|
||||
export * from './authProvider'
|
||||
export * from './i18nProvider'
|
Reference in New Issue
Block a user