feat: 接入真实登录鉴权流程
This commit is contained in:
@@ -25,12 +25,12 @@ export const usePermissionStore = defineStore("pure-permission", {
|
||||
actions: {
|
||||
/** 组装整体路由生成的菜单 */
|
||||
handleWholeMenus(routes: any[]) {
|
||||
this.wholeMenus = filterNoPermissionTree(
|
||||
const menus = filterNoPermissionTree(
|
||||
filterTree(ascending(this.constantMenus.concat(routes)))
|
||||
);
|
||||
this.flatteningRoutes = formatFlatteningRoutes(
|
||||
this.constantMenus.concat(routes) as any
|
||||
);
|
||||
|
||||
this.wholeMenus = menus;
|
||||
this.flatteningRoutes = formatFlatteningRoutes(menus as any);
|
||||
},
|
||||
/** 监听缓存页面是否存在于标签页,不存在则删除 */
|
||||
clearCache() {
|
||||
|
||||
+162
-55
@@ -4,42 +4,110 @@ import {
|
||||
store,
|
||||
router,
|
||||
resetRouter,
|
||||
routerArrays,
|
||||
storageLocal
|
||||
} from "../utils";
|
||||
import {
|
||||
type UserResult,
|
||||
type RefreshTokenResult,
|
||||
getLogin,
|
||||
refreshTokenApi
|
||||
type AuthUser,
|
||||
type LoginInput,
|
||||
type LoginResult,
|
||||
type PermissionMenu,
|
||||
getCurrentPermissions,
|
||||
getCurrentUser,
|
||||
loginAdmin
|
||||
} from "@/api/user";
|
||||
import { usePermissionStoreHook } from "./permission";
|
||||
import { useMultiTagsStoreHook } from "./multiTags";
|
||||
import { type DataInfo, setToken, removeToken, userKey } from "@/utils/auth";
|
||||
import {
|
||||
type DataInfo,
|
||||
setToken,
|
||||
getToken,
|
||||
removeToken,
|
||||
userKey
|
||||
} from "@/utils/auth";
|
||||
|
||||
const savedUser = storageLocal().getItem<DataInfo<number>>(userKey);
|
||||
|
||||
function resolveExpiresAt(expiresIn: string) {
|
||||
const matched = /^(\d+)([smhd])$/.exec(expiresIn);
|
||||
const amount = matched ? Number(matched[1]) : 2;
|
||||
const unit = matched?.[2] ?? "h";
|
||||
const unitMap = {
|
||||
s: 1000,
|
||||
m: 60 * 1000,
|
||||
h: 60 * 60 * 1000,
|
||||
d: 24 * 60 * 60 * 1000
|
||||
};
|
||||
|
||||
return Date.now() + amount * unitMap[unit];
|
||||
}
|
||||
|
||||
function toUserContext(
|
||||
user: AuthUser,
|
||||
token: Pick<DataInfo<number>, "accessToken" | "expires">,
|
||||
permissionMenus: PermissionMenu[],
|
||||
permissions: string[]
|
||||
): DataInfo<number> {
|
||||
return {
|
||||
...token,
|
||||
username: user.username,
|
||||
nickname: user.displayName,
|
||||
accountType: user.accountType,
|
||||
storeId: user.storeId,
|
||||
storeName: user.storeName,
|
||||
roles: user.roles.map(role => role.code),
|
||||
permissions,
|
||||
permissionMenus,
|
||||
canManage: user.canManage
|
||||
};
|
||||
}
|
||||
|
||||
function collectMenuTags(menus: any[]) {
|
||||
const result = [];
|
||||
|
||||
menus.forEach(item => {
|
||||
if (item?.children?.length) {
|
||||
result.push(...collectMenuTags(item.children));
|
||||
return;
|
||||
}
|
||||
|
||||
if (item?.meta?.showLink === false || item?.meta?.hiddenTag) return;
|
||||
result.push(item);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export const useUserStore = defineStore("pure-user", {
|
||||
state: (): userType => ({
|
||||
// 头像
|
||||
avatar: storageLocal().getItem<DataInfo<number>>(userKey)?.avatar ?? "",
|
||||
// 用户名
|
||||
username:
|
||||
storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? "admin",
|
||||
// 昵称
|
||||
nickname:
|
||||
storageLocal().getItem<DataInfo<number>>(userKey)?.nickname ??
|
||||
"系统管理员",
|
||||
// 页面级别权限
|
||||
roles: storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [
|
||||
"admin"
|
||||
],
|
||||
// 按钮级别权限
|
||||
permissions:
|
||||
storageLocal().getItem<DataInfo<number>>(userKey)?.permissions ?? [],
|
||||
avatar: "",
|
||||
username: savedUser?.username ?? "",
|
||||
nickname: savedUser?.nickname ?? "",
|
||||
accountType: savedUser?.accountType ?? "",
|
||||
storeId: savedUser?.storeId,
|
||||
storeName: savedUser?.storeName,
|
||||
roles: savedUser?.roles ?? [],
|
||||
permissions: savedUser?.permissions ?? [],
|
||||
permissionMenus: savedUser?.permissionMenus ?? [],
|
||||
canManage: savedUser?.canManage ?? false,
|
||||
authLoaded: false,
|
||||
// 是否勾选了登录页的免登录
|
||||
isRemembered: false,
|
||||
// 登录页的免登录存储几天,默认7天
|
||||
loginDay: 7
|
||||
}),
|
||||
actions: {
|
||||
/** 写入后端认证上下文,并同步 pure-admin 仍在读取的用户字段。 */
|
||||
SET_USER_CONTEXT(data: Partial<DataInfo<number>>) {
|
||||
this.username = data.username ?? "";
|
||||
this.nickname = data.nickname ?? "";
|
||||
this.accountType = data.accountType ?? "";
|
||||
this.storeId = data.storeId;
|
||||
this.storeName = data.storeName;
|
||||
this.roles = data.roles ?? [];
|
||||
this.permissions = data.permissions ?? [];
|
||||
this.permissionMenus = data.permissionMenus ?? [];
|
||||
this.canManage = data.canManage ?? false;
|
||||
},
|
||||
/** 存储头像 */
|
||||
SET_AVATAR(avatar: string) {
|
||||
this.avatar = avatar;
|
||||
@@ -68,44 +136,83 @@ export const useUserStore = defineStore("pure-user", {
|
||||
SET_LOGINDAY(value: number) {
|
||||
this.loginDay = Number(value);
|
||||
},
|
||||
/** 登入 */
|
||||
async loginByUsername(data) {
|
||||
return new Promise<UserResult>((resolve, reject) => {
|
||||
getLogin(data)
|
||||
.then(data => {
|
||||
if (data?.success) setToken(data.data);
|
||||
resolve(data);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
syncPermissionMenus() {
|
||||
const permissionStore = usePermissionStoreHook();
|
||||
|
||||
permissionStore.handleWholeMenus([]);
|
||||
if (!useMultiTagsStoreHook().getMultiTagsCache) {
|
||||
useMultiTagsStoreHook().handleTags(
|
||||
"equal",
|
||||
collectMenuTags(permissionStore.wholeMenus)
|
||||
);
|
||||
}
|
||||
},
|
||||
/** 前端登出(不调用接口) */
|
||||
/** 登入:按 API.md 推荐流程完成 login -> me -> permissions/me。 */
|
||||
async loginByUsername(data: LoginInput) {
|
||||
const loginResult: LoginResult = await loginAdmin(data);
|
||||
|
||||
if (loginResult?.success) {
|
||||
const context = toUserContext(
|
||||
loginResult.data.user,
|
||||
{
|
||||
accessToken: loginResult.data.token,
|
||||
expires: resolveExpiresAt(loginResult.data.expiresIn)
|
||||
},
|
||||
[],
|
||||
loginResult.data.user.permissions
|
||||
);
|
||||
setToken(context);
|
||||
this.SET_USER_CONTEXT(context);
|
||||
await this.loadAuthContext(true);
|
||||
}
|
||||
|
||||
return loginResult;
|
||||
},
|
||||
/** 页面刷新或重新进入受保护页面时,向后端校验 token 并恢复权限上下文。 */
|
||||
async loadAuthContext(force = false) {
|
||||
const token = getToken();
|
||||
|
||||
if (!token?.accessToken) {
|
||||
throw new Error("请先登录");
|
||||
}
|
||||
|
||||
if (this.authLoaded && !force) {
|
||||
this.syncPermissionMenus();
|
||||
return;
|
||||
}
|
||||
|
||||
const [userResult, permissionResult] = await Promise.all([
|
||||
getCurrentUser(),
|
||||
getCurrentPermissions()
|
||||
]);
|
||||
|
||||
const context = toUserContext(
|
||||
userResult.data,
|
||||
token,
|
||||
permissionResult.data.menus,
|
||||
permissionResult.data.permissions
|
||||
);
|
||||
setToken(context);
|
||||
this.SET_USER_CONTEXT(context);
|
||||
this.authLoaded = true;
|
||||
this.syncPermissionMenus();
|
||||
},
|
||||
/** 前端登出(后端当前无登出接口) */
|
||||
logOut() {
|
||||
this.username = "admin";
|
||||
this.nickname = "系统管理员";
|
||||
this.roles = ["admin"];
|
||||
this.username = "";
|
||||
this.nickname = "";
|
||||
this.accountType = "";
|
||||
this.storeId = undefined;
|
||||
this.storeName = undefined;
|
||||
this.roles = [];
|
||||
this.permissions = [];
|
||||
this.permissionMenus = [];
|
||||
this.canManage = false;
|
||||
this.authLoaded = false;
|
||||
removeToken();
|
||||
useMultiTagsStoreHook().handleTags("equal", [...routerArrays]);
|
||||
useMultiTagsStoreHook().handleTags("equal", []);
|
||||
resetRouter();
|
||||
router.push("/employees");
|
||||
},
|
||||
/** 刷新`token` */
|
||||
async handRefreshToken(data) {
|
||||
return new Promise<RefreshTokenResult>((resolve, reject) => {
|
||||
refreshTokenApi(data)
|
||||
.then(data => {
|
||||
if (data) {
|
||||
setToken(data.data);
|
||||
resolve(data);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
router.push("/login");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -40,8 +40,20 @@ export type userType = {
|
||||
avatar?: string;
|
||||
username?: string;
|
||||
nickname?: string;
|
||||
accountType?: "SUPER_ADMIN" | "EMPLOYEE" | "";
|
||||
storeId?: number;
|
||||
storeName?: string;
|
||||
roles?: Array<string>;
|
||||
permissions?: Array<string>;
|
||||
permissionMenus?: Array<{
|
||||
key: string;
|
||||
title: string;
|
||||
icon?: string;
|
||||
permission: string;
|
||||
actions: string[];
|
||||
}>;
|
||||
canManage?: boolean;
|
||||
authLoaded?: boolean;
|
||||
isRemembered?: boolean;
|
||||
loginDay?: number;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user