Токены, правильная работа

This commit is contained in:
Халимов Рустам
2026-04-19 22:13:20 +03:00
parent 70acad56fb
commit 9e715fe3ab
18 changed files with 422 additions and 45 deletions

View File

@@ -5,6 +5,7 @@ import type { User } from '../../../core/domain/types';
interface AuthState {
token: string | null;
refreshToken: string | null;
user: User | null;
isLoading: boolean;
error: string | null;
@@ -23,6 +24,9 @@ export const useAuthStore = create<AuthState>((set, get) => ({
if (t) AuthApi.setToken(t);
return t;
})(),
refreshToken: (() => {
return localStorage.getItem('knot_refresh_token');
})(),
user: null,
isLoading: true,
error: null,
@@ -33,17 +37,20 @@ export const useAuthStore = create<AuthState>((set, get) => ({
try {
const res = await AuthApi.getConfig();
set({ config: res });
} catch {}
} catch { }
},
login: async (username, password) => {
try {
set({ error: null, isLoading: true });
const { token, user } = await AuthApi.login(username, password);
const { token, refreshToken, user } = await AuthApi.login(username, password);
localStorage.setItem('knot_token', token);
if (refreshToken) {
localStorage.setItem('knot_refresh_token', refreshToken);
}
AuthApi.setToken(token);
connectSocket(token);
set({ token, user, isLoading: false });
set({ token, refreshToken, user, isLoading: false });
await get().fetchConfig();
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
@@ -55,11 +62,14 @@ export const useAuthStore = create<AuthState>((set, get) => ({
register: async (username, displayName, password, bio) => {
try {
set({ error: null, isLoading: true });
const { token, user } = await AuthApi.register(username, displayName, password, bio);
const { token, refreshToken, user } = await AuthApi.register(username, displayName, password, bio);
localStorage.setItem('knot_token', token);
if (refreshToken) {
localStorage.setItem('knot_refresh_token', refreshToken);
}
AuthApi.setToken(token);
connectSocket(token);
set({ token, user, isLoading: false });
set({ token, refreshToken, user, isLoading: false });
await get().fetchConfig();
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
@@ -70,9 +80,10 @@ export const useAuthStore = create<AuthState>((set, get) => ({
logout: () => {
localStorage.removeItem('knot_token');
localStorage.removeItem('knot_refresh_token');
AuthApi.setToken(null);
disconnectSocket();
set({ token: null, user: null });
set({ token: null, refreshToken: null, user: null });
},
checkAuth: async () => {
@@ -121,11 +132,12 @@ export const useAuthStore = create<AuthState>((set, get) => ({
errorMsg.includes('Недействительный токен') ||
errorMsg.includes('Требуется авторизация')
) {
localStorage.removeItem('knot_token');
set({ token: null, user: null, isLoading: false });
localStorage.removeItem('knot_token');
localStorage.removeItem('knot_refresh_token');
set({ token: null, refreshToken: null, user: null, isLoading: false });
} else {
// Keep the token but stop loading if we're just offline/network error/500
set({ isLoading: false });
// Keep the token but stop loading if we're just offline/network error/500
set({ isLoading: false });
}
},

View File

@@ -3,13 +3,14 @@ import type { User } from '../../../core/domain/types';
export class AuthApi {
static async login(username: string, password: string) {
const response = await httpClient.request<{ accessToken: string; userId: string; username: string; displayName: string }>('/auth/login', {
const response = await httpClient.request<{ accessToken: string; refreshToken: string; userId: string; username: string; displayName: string }>('/auth/login', {
method: 'POST',
body: JSON.stringify({ username, password }),
});
return {
token: response.accessToken,
refreshToken: response.refreshToken,
user: {
id: response.userId,
username: response.username,
@@ -20,13 +21,32 @@ export class AuthApi {
}
static async register(username: string, displayName: string, password: string, bio?: string) {
const response = await httpClient.request<{ accessToken: string; userId: string; username: string; displayName: string }>('/auth/register', {
const response = await httpClient.request<{ accessToken: string; refreshToken: string; userId: string; username: string; displayName: string }>('/auth/register', {
method: 'POST',
body: JSON.stringify({ username, displayName, password, bio }),
});
return {
token: response.accessToken,
refreshToken: response.refreshToken,
user: {
id: response.userId,
username: response.username,
displayName: response.displayName,
avatar: null
} as User
};
}
static async refresh(refreshToken: string) {
const response = await httpClient.request<{ accessToken: string; refreshToken: string; userId: string; username: string; displayName: string }>('/auth/refresh', {
method: 'POST',
body: JSON.stringify({ refreshToken }),
});
return {
token: response.accessToken,
refreshToken: response.refreshToken,
user: {
id: response.userId,
username: response.username,