115 lines
3.8 KiB
TypeScript
115 lines
3.8 KiB
TypeScript
// Ported from legacy henza_admin/src/store/auth/moduleAuth.js
|
|
import { defineStore } from 'pinia';
|
|
import api from '../api/client';
|
|
import { iamAppUrl, tokenName, userName } from '../utils';
|
|
import { useUsersStore } from './users';
|
|
import type { UserInfo } from './users';
|
|
|
|
/**
|
|
* LEGACY BUG, recorded in docs/ADMIN-PORT-PLAN.md (#3).
|
|
*
|
|
* Legacy declared these as FUNCTIONS in Vuex state, not values:
|
|
*
|
|
* const state = {
|
|
* user: () => JSON.parse(localStorage.getItem(...)),
|
|
* token: () => localStorage.getItem(...),
|
|
* }
|
|
*
|
|
* so `store.state.auth.token` was a function object — always truthy, even when
|
|
* logged out. The router guard's `store.state.auth.token && store.state.auth.user`
|
|
* check was therefore dead code that always passed, and the real gate was the
|
|
* separate `localStorage.getItem(token)` read in beforeEach.
|
|
*
|
|
* Here they are getters that return the actual value. The observable behaviour
|
|
* is unchanged, because the real gate was — and still is — the localStorage read;
|
|
* this only removes a permanently-true condition, it does not let anyone in.
|
|
*/
|
|
export const useAuthStore = defineStore('auth', {
|
|
state: () => ({
|
|
userPermission: [] as string[],
|
|
}),
|
|
getters: {
|
|
token: (): string | null => localStorage.getItem(tokenName),
|
|
user: (): UserInfo | null => {
|
|
const raw = localStorage.getItem(userName);
|
|
if (!raw) return null;
|
|
try {
|
|
return JSON.parse(raw);
|
|
} catch {
|
|
return null;
|
|
}
|
|
},
|
|
isLoggedIn(): boolean {
|
|
return Boolean(this.token);
|
|
},
|
|
},
|
|
actions: {
|
|
/**
|
|
* Port of legacy action `login`.
|
|
*
|
|
* Legacy: POST 'admin-login', then
|
|
* dispatch('users/getRoles', data.roles.map(x => x.rid))
|
|
* delete data.roles; delete data.ut
|
|
* commit('INJECT', data)
|
|
*
|
|
* The endpoint name is translated by the mapping layer in api/endpoints.ts.
|
|
*/
|
|
async login(payload: { phone: string; password: string }) {
|
|
const { data } = await api.post('admin-login', payload);
|
|
|
|
const users = useUsersStore();
|
|
users.getRoles((data.roles ?? []).map((x: { rid: string }) => x.rid));
|
|
users.setSuperAdmin(data.is_super_admin);
|
|
|
|
// Legacy stripped these before persisting the user blob. Kept: the panel
|
|
// reads permissions from the store, never from the cached user object.
|
|
const persisted = { ...data };
|
|
delete persisted.roles;
|
|
delete persisted.ut;
|
|
|
|
this.inject(persisted);
|
|
if (data.iamBootstrapUrl) {
|
|
window.location.assign(data.iamBootstrapUrl);
|
|
}
|
|
return persisted;
|
|
},
|
|
|
|
/** Port of legacy mutation INJECT. */
|
|
inject(payload: UserInfo & { api_token: string }) {
|
|
localStorage.setItem(tokenName, payload.api_token);
|
|
// Consumed once by App.vue to show the welcome toast, then removed.
|
|
localStorage.setItem('login', 'true');
|
|
localStorage.setItem(userName, JSON.stringify(payload));
|
|
},
|
|
|
|
/**
|
|
* Not present in legacy — legacy had no logout action at all, which is why
|
|
* its module-scoped `roles` survived a session change (bug #2). Clearing
|
|
* both storage and the roles store is the fix for that.
|
|
*/
|
|
async logout(): Promise<boolean> {
|
|
let central: string | null = null;
|
|
try {
|
|
const { data } = await api.get('admin/auth/sso/logout-url', {
|
|
params: { return_url: iamAppUrl('auth/login') },
|
|
});
|
|
central = data?.logout_url ?? null;
|
|
} catch {
|
|
central = null;
|
|
}
|
|
localStorage.removeItem(tokenName);
|
|
localStorage.removeItem(userName);
|
|
localStorage.removeItem('login');
|
|
sessionStorage.removeItem('gb_admin_iam_sso_checked');
|
|
const users = useUsersStore();
|
|
users.deleteRoles();
|
|
users.deleteUserInfo();
|
|
if (central) {
|
|
window.location.assign(central);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
},
|
|
});
|