feat(client): add auth logic

This commit is contained in:
Vladislav Syrochkin 2025-06-16 12:34:32 +05:00
parent 79cb434ebd
commit c87581c9e2
6 changed files with 70 additions and 34 deletions

View File

@ -1,10 +1,21 @@
import React from 'react'; /* eslint-disable react-hooks/exhaustive-deps */
import React, { useEffect } from 'react';
import { Route, Routes } from 'react-router-dom'; import { Route, Routes } from 'react-router-dom';
import MainLayout from './pages/MainLayout'; import MainLayout from './pages/MainLayout';
import ProtectedRoute from './pages/ProtectedRoute'; import ProtectedRoute from './pages/ProtectedRoute';
import LoginPage from './pages/LoginPage'; import LoginPage from './pages/LoginPage';
import { useSetUserSelector } from './store/userStore';
function App() { function App() {
const setUser = useSetUserSelector();
useEffect(() => {
const storedUser = localStorage.getItem('user');
if (storedUser) {
setUser(JSON.parse(storedUser));
}
}, []);
return ( return (
<div className="App"> <div className="App">
<Routes> <Routes>

View File

@ -1,8 +1,9 @@
import axios from 'axios'; import axios from 'axios';
import { Access, Auth } from '../types/auth'; import { Access, Auth } from '../types/auth';
import { User } from '../types/user'; import { User } from '../types/user';
import { AuthService } from '../services/auth'; import { AuthService } from '../services/authService';
import axiosRetry from 'axios-retry'; import axiosRetry from 'axios-retry';
import { useAuthStore } from '../store/authStore';
const baseURL = `${process.env.REACT_APP_HTTP_PROTOCOL}://${process.env.REACT_APP_API_URL}/api/v1`; const baseURL = `${process.env.REACT_APP_HTTP_PROTOCOL}://${process.env.REACT_APP_API_URL}/api/v1`;
@ -15,7 +16,10 @@ const base = axios.create({
}); });
base.interceptors.request.use((config) => { base.interceptors.request.use((config) => {
const token = localStorage.getItem('accessToken'); if (config.url === '/auth/refresh') {
return config;
}
const token = useAuthStore.getState().accessToken;
if (token) { if (token) {
config.headers.Authorization = `Bearer ${token}`; config.headers.Authorization = `Bearer ${token}`;
} }
@ -43,7 +47,6 @@ base.interceptors.response.use(
async function (error) { async function (error) {
console.log('error', error); console.log('error', error);
const originalRequest = error.response.config; const originalRequest = error.response.config;
console.log('originalRequest._retry', originalRequest);
const urlTokens = error?.request?.responseURL.split('/'); const urlTokens = error?.request?.responseURL.split('/');
const url = urlTokens[urlTokens.length - 1]; const url = urlTokens[urlTokens.length - 1];
console.log('url', url); console.log('url', url);
@ -55,26 +58,43 @@ base.interceptors.response.use(
url !== 'logout' url !== 'logout'
) { ) {
originalRequest._retry = true; originalRequest._retry = true;
const res = await AuthService.refresh().catch(async () => { try {
await AuthService.refresh();
return base(originalRequest);
} catch (error) {
await AuthService.logout(); await AuthService.logout();
}); return new Promise(() => {});
console.log('res', res); }
return await base(originalRequest);
} }
return await Promise.reject(error); return await Promise.reject(error);
} }
); );
interface newAccess {
accessToken: string;
refreshToken: string;
}
const api = { const api = {
// auth // auth
async login(auth: Auth): Promise<Access> { // async login(auth: Auth): Promise<Access> {
console.log(auth); async login(auth: Auth): Promise<newAccess> {
const response = await base.post<Access>('/auth', auth); // const response = (await base.post) <Access> ('/auth', auth);
const response = await base.post<newAccess>('/auth', auth);
return response.data; return response.data;
}, },
async refreshToken(): Promise<Access> { async refreshToken(): Promise<Access> {
const response = await base.post<Access>('/auth/refresh'); const token = localStorage.getItem('refreshToken');
const response = await base.post<Access>(
'/auth/refresh',
{},
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
return response.data; return response.data;
}, },
@ -83,6 +103,13 @@ const api = {
const response = await base.get<User>('/profile'); const response = await base.get<User>('/profile');
return response.data; return response.data;
}, },
async getUsers(page: number, limit: number): Promise<any> {
const response = await base.get<User[]>(
`/account?page=${page}&limit=${limit}`
);
return response.data;
},
}; };
export default api; export default api;

View File

@ -3,6 +3,10 @@ import { useState } from 'react';
import ContentDrawer from '../components/ContentDrawer'; import ContentDrawer from '../components/ContentDrawer';
import UserCreate from '../components/UserCreate'; import UserCreate from '../components/UserCreate';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Button } from 'antd';
import { UserService } from '../services/userService';
import { User } from '../types/user';
import { AuthService } from '../services/authService';
export default function AccountsPage() { export default function AccountsPage() {
const { t } = useTranslation(); const { t } = useTranslation();
@ -11,6 +15,8 @@ export default function AccountsPage() {
const showDrawer = () => setOpen(true); const showDrawer = () => setOpen(true);
const closeDrawer = () => setOpen(false); const closeDrawer = () => setOpen(false);
const [accounts, setAccounts] = useState<User[]>([]);
return ( return (
<> <>
<Header <Header

View File

@ -5,7 +5,7 @@ import {
EyeTwoTone, EyeTwoTone,
UserOutlined, UserOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { AuthService } from '../services/auth'; import { AuthService } from '../services/authService';
import { Auth } from '../types/auth'; import { Auth } from '../types/auth';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';

View File

@ -9,8 +9,6 @@ import RunningProcessesPage from './RunningProcessesPage';
import AccountsPage from './AccountsPage'; import AccountsPage from './AccountsPage';
import EventsListPage from './EventsListPage'; import EventsListPage from './EventsListPage';
import ConfigurationPage from './ConfigurationPage'; import ConfigurationPage from './ConfigurationPage';
import { useSetUserSelector } from '../store/user';
import { UserService } from '../services/user';
export default function MainLayout() { export default function MainLayout() {
const navigate = useNavigate(); const navigate = useNavigate();
@ -21,8 +19,6 @@ export default function MainLayout() {
const [width, setWidth] = useState<number | string>('15%'); const [width, setWidth] = useState<number | string>('15%');
const [collapsedWidth, setCollapsedWidth] = useState(50); const [collapsedWidth, setCollapsedWidth] = useState(50);
const setUser = useSetUserSelector();
const calculateWidths = () => { const calculateWidths = () => {
const windowWidth = window.innerWidth; const windowWidth = window.innerWidth;
const expanded = Math.min(Math.max(windowWidth * 0.15, 180), 240); const expanded = Math.min(Math.max(windowWidth * 0.15, 180), 240);
@ -58,21 +54,6 @@ export default function MainLayout() {
navigate(key); navigate(key);
} }
useEffect(() => {
const token = localStorage.getItem('accessToken');
if (!token) {
navigate('/login');
} else {
if (localStorage.getItem('user')) {
setUser(JSON.parse(localStorage.getItem('user') as string));
} else {
UserService.getProfile().then((user) => {
setUser(user);
});
}
}
}, []);
return ( return (
<Layout style={{ minHeight: '100vh' }}> <Layout style={{ minHeight: '100vh' }}>
<Sider <Sider

View File

@ -1,8 +1,19 @@
/* eslint-disable react-hooks/exhaustive-deps */
// ProtectedRoute.js // ProtectedRoute.js
import { Outlet } from 'react-router-dom'; import { Outlet, useNavigate } from 'react-router-dom';
import React from 'react'; import React, { useEffect } from 'react';
import { useUserSelector } from '../store/userStore';
const ProtectedRoute = (): React.JSX.Element => { const ProtectedRoute = (): React.JSX.Element => {
const navigate = useNavigate();
const user = useUserSelector();
useEffect(() => {
if (!user?.id) {
navigate('/login');
}
}, [user]);
return <Outlet />; return <Outlet />;
}; };
export default ProtectedRoute; export default ProtectedRoute;