fix authProvider
for added custom
auth
This commit is contained in:
parent
da3a162adb
commit
35e4718630
@ -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",
|
||||
|
@ -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)
|
||||
|
@ -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}
|
||||
|
@ -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)
|
||||
|
@ -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
18
src/providers/data.ts
Normal 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)
|
Loading…
Reference in New Issue
Block a user