175 lines
4.1 KiB
TypeScript
175 lines
4.1 KiB
TypeScript
import type {AuthProvider} from '@refinedev/core'
|
||
import axios, {AxiosError} from 'axios'
|
||
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)
|
||
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>(`${BACKEND_URL}/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(
|
||
`${BACKEND_URL}/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(`${BACKEND_URL}/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}
|
||
},
|
||
}
|