fix(client): logout
Some checks failed
Backend Check Build (NixCN CMS) TeamCity build finished
Client CMS Check Build (NixCN CMS) TeamCity build failed

Signed-off-by: Noa Virellia <noa@requiem.garden>
This commit is contained in:
2026-01-30 22:48:09 +08:00
parent 88a14bfced
commit 6ea414bc88
15 changed files with 186 additions and 150 deletions

View File

@@ -1,13 +1,12 @@
import { isEmpty, isNil } from 'lodash-es';
import { client } from '@/client/client.gen';
import { router } from './router';
import {
clearTokens,
doRefreshToken,
getAccessToken,
getRefreshToken,
getToken,
logout,
setAccessToken,
setRefreshToken,
setToken,
} from './token';
export function configInternalApiClient() {
@@ -19,8 +18,8 @@ export function configInternalApiClient() {
});
client.interceptors.request.use((request) => {
const token = getToken();
if (token) {
const token = getAccessToken();
if (!isNil(token) && !isEmpty(token)) {
request.headers.set('Authorization', `Bearer ${token}`);
}
return request;
@@ -28,14 +27,21 @@ export function configInternalApiClient() {
client.interceptors.response.use(async (response, request, options) => {
if (response.status === 401) {
const refreshToken = getRefreshToken();
// Avoid infinite loop if the refresh token request itself fails
if (!request.url.includes('/auth/refresh') && !isNil(refreshToken)) {
try {
const refreshResponse = await doRefreshToken();
if (request.url.includes('/auth/refresh')) {
// Refresh token failed, clear tokens and redirect to login page
logout('Session expired');
}
else {
const refreshToken = getRefreshToken();
if (isNil(refreshToken) || isEmpty(refreshToken)) {
logout('You are not logged in');
}
else {
const refreshResponse = await doRefreshToken(refreshToken);
if (!isEmpty(refreshResponse)) {
const { access_token, refresh_token } = refreshResponse;
setToken(access_token!);
setAccessToken(access_token!);
setRefreshToken(refresh_token!);
const fetchFn = options.fetch ?? globalThis.fetch;
@@ -50,11 +56,6 @@ export function configInternalApiClient() {
});
}
}
catch (e) {
clearTokens();
await router.navigate({ to: '/authorize' });
return response;
}
}
}
return response;

View File

@@ -1,40 +1,52 @@
import type { ServiceAuthTokenResponse } from '@/client';
import { toast } from 'sonner';
import { postAuthRefresh } from '@/client';
import { router } from './router';
export function setToken(token: string) {
localStorage.setItem('token', token);
const ACCESS_TOKEN_LOCALSTORAGE_KEY = 'token';
const REFRESH_TOKEN_LOCALSTORAGE_KEY = 'refreshToken';
export function setAccessToken(token: string) {
localStorage.setItem(ACCESS_TOKEN_LOCALSTORAGE_KEY, token);
}
export function getToken() {
return localStorage.getItem('token');
export function getAccessToken() {
return localStorage.getItem(ACCESS_TOKEN_LOCALSTORAGE_KEY);
}
export function removeToken() {
localStorage.removeItem('token');
}
export function hasToken() {
return getToken() !== null;
export function removeAccessToken() {
localStorage.removeItem(ACCESS_TOKEN_LOCALSTORAGE_KEY);
}
export function setRefreshToken(refreshToken: string) {
localStorage.setItem('refreshToken', refreshToken);
localStorage.setItem(REFRESH_TOKEN_LOCALSTORAGE_KEY, refreshToken);
}
export function getRefreshToken() {
return localStorage.getItem('refreshToken');
return localStorage.getItem(REFRESH_TOKEN_LOCALSTORAGE_KEY);
}
export function removeRefreshToken() {
localStorage.removeItem(REFRESH_TOKEN_LOCALSTORAGE_KEY);
}
export function clearTokens() {
removeToken();
setRefreshToken('');
removeAccessToken();
removeRefreshToken();
}
export async function doRefreshToken(): Promise<ServiceAuthTokenResponse | undefined> {
export async function doRefreshToken(refreshToken: string): Promise<ServiceAuthTokenResponse | undefined> {
const { data } = await postAuthRefresh({
body: {
refresh_token: getRefreshToken()!,
refresh_token: refreshToken,
},
});
return data?.data;
}
export function logout(message: string = 'Logged out') {
clearTokens();
void router.navigate({ to: '/authorize' }).then(() => {
toast.error(message);
});
}