Skip to content

Commit bafb5b0

Browse files
committed
feat: implement autologin functionality and refactor redirect logic
1 parent bd3f3d8 commit bafb5b0

1 file changed

Lines changed: 102 additions & 14 deletions

File tree

adminforth/spa/src/utils/utils.ts

Lines changed: 102 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,113 @@ import type { AdminForthActionFront, AdminForthResourceColumnInputCommon, AdminF
1212
import { i18nInstance } from '../i18n'
1313
import { useI18n } from 'vue-i18n';
1414
import { onBeforeRouteLeave } from 'vue-router';
15+
import { reconnect } from '@/websocket';
1516

1617

1718

1819
const LS_LANG_KEY = `afLanguage`;
1920
const MAX_CONSECUTIVE_EMPTY_RESULTS = 2;
2021
const ITEMS_PER_PAGE_LIMIT = 100;
22+
const AUTOLOGIN_QUERY_PARAM = 'autologin';
23+
24+
export function getAutologinCredentials(autologin: unknown): { username: string, password: string } | null {
25+
if (typeof autologin !== 'string') {
26+
return null;
27+
}
28+
29+
const separatorIndex = autologin.indexOf(':');
30+
if (separatorIndex === -1) {
31+
return null;
32+
}
33+
34+
return {
35+
username: autologin.slice(0, separatorIndex),
36+
password: autologin.slice(separatorIndex + 1),
37+
};
38+
}
39+
40+
function buildLoginRedirectQuery() {
41+
const { path, query } = router.currentRoute.value;
42+
const nextQuery = new URLSearchParams();
43+
44+
for (const [key, rawValue] of Object.entries(query)) {
45+
if (key === AUTOLOGIN_QUERY_PARAM || rawValue == null) {
46+
continue;
47+
}
48+
49+
if (Array.isArray(rawValue)) {
50+
rawValue.forEach((value) => {
51+
if (value != null) {
52+
nextQuery.append(key, value);
53+
}
54+
});
55+
continue;
56+
}
57+
58+
nextQuery.set(key, rawValue);
59+
}
60+
61+
const next = nextQuery.size > 0 ? `${path}?${nextQuery.toString()}` : path;
62+
const autologin = typeof query[AUTOLOGIN_QUERY_PARAM] === 'string'
63+
? query[AUTOLOGIN_QUERY_PARAM]
64+
: undefined;
65+
66+
return {
67+
next,
68+
autologin,
69+
};
70+
}
71+
72+
async function tryAutologin(autologin: string): Promise<boolean> {
73+
const credentials = getAutologinCredentials(autologin);
74+
if (!credentials) {
75+
return false;
76+
}
77+
78+
const response = await fetch(`${import.meta.env.VITE_ADMINFORTH_PUBLIC_PATH || ''}/adminapi/v1/login`, {
79+
method: 'POST',
80+
headers: {
81+
'Content-Type': 'application/json',
82+
'accept-language': localStorage.getItem(LS_LANG_KEY) || 'en',
83+
},
84+
body: JSON.stringify({
85+
username: credentials.username,
86+
password: credentials.password,
87+
rememberMe: false,
88+
}),
89+
});
90+
91+
const loginResponse = await response.json();
92+
if (loginResponse?.error) {
93+
return false;
94+
}
95+
96+
const userStore = useUserStore();
97+
const coreStore = useCoreStore();
98+
userStore.authorize();
99+
reconnect();
100+
await coreStore.fetchMenuAndResource();
101+
return !!coreStore.adminUser;
102+
}
103+
104+
export async function redirectToLogin() {
105+
const currentPath = router.currentRoute.value.path;
106+
const homeRoute = router.getRoutes().find(route => route.name === 'home');
107+
const homePagePath = (homeRoute?.redirect as string) || '/';
108+
const { next, autologin } = buildLoginRedirectQuery();
109+
110+
if (autologin && await tryAutologin(autologin)) {
111+
return;
112+
}
113+
114+
const query: Record<string, string> = {};
115+
116+
if (currentPath !== '/login' && currentPath !== homePagePath) {
117+
query.next = next;
118+
}
119+
120+
await router.push({ name: 'login', query });
121+
}
21122

22123
export async function callApi({path, method, body, headers, silentError = false, abortSignal}: {
23124
path: string, method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
@@ -43,20 +144,7 @@ export async function callApi({path, method, body, headers, silentError = false,
43144
if (r.status == 401 ) {
44145
useUserStore().unauthorize();
45146
useCoreStore().resetAdminUser();
46-
const currentPath = router.currentRoute.value.path;
47-
const homeRoute = router.getRoutes().find(route => route.name === 'home');
48-
const homePagePath = (homeRoute?.redirect as string) || '/';
49-
let next = '';
50-
if (currentPath !== '/login' && currentPath !== homePagePath) {
51-
if (Object.keys(router.currentRoute.value.query).length > 0) {
52-
next = currentPath + '?' + Object.entries(router.currentRoute.value.query).map(([key, value]) => `${key}=${value}`).join('&');
53-
} else {
54-
next = currentPath;
55-
}
56-
await router.push({ name: 'login', query: { next: next } });
57-
} else {
58-
await router.push({ name: 'login' });
59-
}
147+
await redirectToLogin();
60148
return null;
61149
}
62150
return await r.json();

0 commit comments

Comments
 (0)