fix authProvider for added custom auth

This commit is contained in:
maxim 2025-03-28 00:29:13 +03:00
parent da3a162adb
commit 35e4718630
6 changed files with 90 additions and 64 deletions

View File

@ -22,6 +22,7 @@
"easymde": "^2.19.0",
"i18next": "^24.2.2",
"js-cookie": "^3.0.5",
"jwt-decode": "^4.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-hook-form": "^7.30.0",

View File

@ -62,6 +62,9 @@ importers:
js-cookie:
specifier: ^3.0.5
version: 3.0.5
jwt-decode:
specifier: ^4.0.0
version: 4.0.0
react:
specifier: ^18.0.0
version: 18.3.1
@ -2067,6 +2070,10 @@ packages:
jsonfile@6.1.0:
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
jwt-decode@4.0.0:
resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==}
engines: {node: '>=18'}
kbar@0.1.0-beta.45:
resolution: {integrity: sha512-kXvjthqPLoWZXlxLJPrFKioskNdQv1O3Ukg5mqq2ExK3Ix1qvYT3W/ACDRIv/e/CHxPWZoTriB4oFbQ6UCSX5g==}
peerDependencies:
@ -5408,6 +5415,8 @@ snapshots:
optionalDependencies:
graceful-fs: 4.2.11
jwt-decode@4.0.0: {}
kbar@0.1.0-beta.45(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)

View File

@ -4,7 +4,7 @@ import {RefineKbar, RefineKbarProvider} from '@refinedev/kbar'
import {ErrorComponent, useNotificationProvider, RefineSnackbarProvider, ThemedLayoutV2} from '@refinedev/mui'
import dataProvider from '@refinedev/simple-rest'
import {customDataProvider} from './providers/data'
import CssBaseline from '@mui/material/CssBaseline'
import GlobalStyles from '@mui/material/GlobalStyles'
import {BrowserRouter, Route, Routes, Outlet} from 'react-router'
@ -29,7 +29,6 @@ import {RouteList, RouteCreate, RouteEdit, RouteShow} from './pages/route'
import {CountryIcon, CityIcon, CarrierIcon, MediaIcon, ArticleIcon, SightIcon, StationIcon, VehicleIcon, RouteIcon} from './components/ui/Icons'
import SidebarTitle from './components/ui/SidebarTitle'
import {BACKEND_URL} from './lib/constants'
function App() {
return (
@ -41,7 +40,7 @@ function App() {
<RefineSnackbarProvider>
<DevtoolsProvider>
<Refine
dataProvider={dataProvider(BACKEND_URL)}
dataProvider={customDataProvider}
notificationProvider={useNotificationProvider}
routerProvider={routerBindings}
authProvider={authProvider}

View File

@ -1,11 +1,24 @@
import type {AuthProvider} from '@refinedev/core'
import axios, {AxiosError} from 'axios'
// import {BACKEND_URL} from './lib/constants'
const API_URL = 'https://wn.krbl.ru'
import {BACKEND_URL} from './lib/constants'
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)
@ -13,41 +26,26 @@ class AuthError extends Error {
}
}
const MOCK_USER = {
email: 'test@wn.ru',
password: 'testwn',
name: 'Константин Иванов',
avatar: 'https://i.pravatar.cc/300',
// roles: ['admin'],
interface JWTPayload {
user_id: number
email: string
is_admin: boolean
exp: number
}
export const authProvider: AuthProvider = {
login: async ({email, password}) => {
try {
if (email === MOCK_USER.email && password === MOCK_USER.password) {
const mockResponse = {
token: 'mock-jwt-token',
user: MOCK_USER,
}
localStorage.setItem(TOKEN_KEY, mockResponse.token)
localStorage.setItem('user', JSON.stringify(mockResponse.user))
return {
success: true,
redirectTo: '/',
}
}
// If not mock user, try real API
const response = await axios.post(`${API_URL}/auth/login`, {
const response = await axios.post<AuthResponse>(`${BACKEND_URL}/auth/login`, {
email,
password,
})
if (response.data.token) {
localStorage.setItem(TOKEN_KEY, response.data.token)
localStorage.setItem('user', JSON.stringify(response.data.user))
const {token, user} = response.data
if (token) {
localStorage.setItem(TOKEN_KEY, token)
localStorage.setItem('user', JSON.stringify(user))
return {
success: true,
@ -57,16 +55,18 @@ export const authProvider: AuthProvider = {
throw new AuthError('Неверный email или пароль')
} catch (error) {
const errorMessage = (error as AxiosError<ErrorResponse>)?.response?.data?.message || 'Неверный email или пароль'
return {
success: false,
error: new AuthError('Неверный email или пароль'),
error: new AuthError(errorMessage),
}
}
},
logout: async () => {
try {
await axios.post(
`${API_URL}/auth/logout`,
`${BACKEND_URL}/auth/logout`,
{},
{
headers: {
@ -87,8 +87,6 @@ export const authProvider: AuthProvider = {
},
check: async () => {
const token = localStorage.getItem(TOKEN_KEY)
const user = localStorage.getItem('user')
if (!token) {
return {
authenticated: false,
@ -96,22 +94,16 @@ export const authProvider: AuthProvider = {
}
}
// If using mock token, skip API verification
if (token === 'mock-jwt-token' && user) {
return {
authenticated: true,
}
}
// For real tokens, verify with API
try {
const response = await axios.get(`${API_URL}/auth/me`, {
const response = await axios.get(`${BACKEND_URL}/auth/me`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
if (response.status === 200) {
// Обновляем информацию о пользователе
localStorage.setItem('user', JSON.stringify(response.data))
return {
authenticated: true,
}
@ -129,7 +121,6 @@ export const authProvider: AuthProvider = {
return {
authenticated: false,
redirectTo: '/login',
error: new AuthError('Пожалуйста, войдите в систему'),
}
},
getPermissions: async () => {
@ -137,25 +128,31 @@ export const authProvider: AuthProvider = {
if (!token) return null
try {
const response = await axios.get(`${API_URL}/auth/permissions`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
return response.data.permissions
} catch (error) {
return null
const decoded = jwtDecode<JWTPayload>(token)
return decoded.is_admin ? ['admin'] : ['user']
} catch {
return ['user']
}
},
getIdentity: async () => {
const token = localStorage.getItem(TOKEN_KEY)
const user = localStorage.getItem('user')
if (user) {
return JSON.parse(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
}
return null
},
onError: async (error) => {
console.error('Ошибка:', error)
const status = (error as AxiosError)?.response?.status
if (status === 401 || status === 403) {
localStorage.removeItem(TOKEN_KEY)

View File

@ -6,12 +6,14 @@ export const Login = () => {
<AuthPage
type="login"
title={<ThemedTitleV2 collapsed={false} text="Белые Ночи" icon={<ProjectIcon style={{color: '#7f6b58'}} />} />}
formProps={{
defaultValues: {
email: 'test@wn.ru',
password: 'testwn',
},
}}
// formProps={
// {
// // defaultValues: {
// // email: 'test@wn.ru',
// // password: 'testwn',
// // },
// }
// }
/>
)
}

18
src/providers/data.ts Normal file
View File

@ -0,0 +1,18 @@
import dataProvider from '@refinedev/simple-rest'
import axios from 'axios'
import {BACKEND_URL} from '../lib/constants'
import {TOKEN_KEY} from '../authProvider'
const axiosInstance = axios.create()
axiosInstance.interceptors.request.use((config) => {
const token = localStorage.getItem(TOKEN_KEY)
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
export const customDataProvider = dataProvider(BACKEND_URL, axiosInstance)