pig-ui/doc/router.md

5.7 KiB
Raw Blame History

登录流程路由拦截

登录

登录通过pinia 调用一步接口将返回的token 通过 Session.set('token', res.access_token); 保存下来。

export const Session = {
	// 设置临时缓存
	set(key: string, val: any) {
		if (key === 'token') return Cookies.set(key, val);
		window.sessionStorage.setItem(key, JSON.stringify(val));
	},
	// 获取临时缓存
	get(key: string) {
		if (key === 'token') return Cookies.get(key);
		let json = <string>window.sessionStorage.getItem(key);
		return JSON.parse(json);
	},
	// 移除临时缓存
	remove(key: string) {
		if (key === 'token') return Cookies.remove(key);
		window.sessionStorage.removeItem(key);
	},
	// 移除全部临时缓存
	clear() {
		Cookies.remove('token');
		window.sessionStorage.clear();
	},
};

根据代码可以看出 如果是存储的是token 则存储到 cookies 中 否则存储到 sessionStorage

路由拦截

通过路由的加载前拦截中

router.beforeEach(async (to, from, next) => {
	NProgress.configure({ showSpinner: false });
	if (to.meta.title) NProgress.start();
	const token = Session.get('token');
	if (to.path === '/login' && !token) {
		next();
		NProgress.done();
	} else {
		if (!token) {
			next(`/login?redirect=${to.path}&params=${JSON.stringify(to.query ? to.query : to.params)}`);
			Session.clear();
			NProgress.done();
		} else if (token && to.path === '/login') {
			next('/home');
			NProgress.done();
		} else {
			const storesRoutesList = useRoutesList(pinia);
			const { routesList } = storeToRefs(storesRoutesList);
			if (routesList.value.length === 0) {
				// 后端控制路由:路由数据初始化,防止刷新时丢失
				await initBackEndControlRoutes();
				next({ path: to.path, query: to.query });
			} else {
				next();
			}
		}
	}
});

显而易见如果没有token 信息则跳转到登录页面并且带着当前页面的信息,以便登录成功后跳转回之前的页面 有token 则处理是不是login 页面。 在不是login 页面的时候 查询 pinia 中是否有存储的路由和菜单信息,如果没有则进行路由初始化

export async function initBackEndControlRoutes() {
    // 界面 loading 动画开始执行
    if (window.nextLoading === undefined) NextLoading.start();
    // 无 token 停止执行下一步
    if (!Session.get('token')) return false;
    // 触发初始化用户信息 pinia
    await useUserInfo().setUserInfos();
    // 获取路由菜单数据
    const res = await getBackEndControlRoutes();
    // 无登录权限时,添加判断
    // https://gitee.com/lyt-top/vue-next-admin/issues/I64HVO
    if (res.data.length <= 0) return Promise.resolve(true);
    // 存储接口原始路由未处理component根据需求选择使用
    useRequestOldRoutes().setRequestOldRoutes(JSON.parse(JSON.stringify(res.data)));
    // 处理路由component替换 dynamicRoutes/@/router/route第一个顶级 children 的路由
    dynamicRoutes[0].children = [...home,...await backEndComponent(res.data), ...staticConfigRoutes]
    // 添加动态路由
    await setAddRoute();
    // 设置路由到 pinia routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
    await setFilterMenuAndCacheTagsViewRoutes();
}
  1. 整体逻辑是校验token 是否存储,
  2. 获取登录用户的信息 await useUserInfo().setUserInfos()
  3. 获取登录用户的菜单信息 const res = await getBackEndControlRoutes()
  4. 讲菜单信息动态添加到前端可以读取到的内容中,供左侧菜单使用 dynamicRoutes[0].children = [...home,...await backEndComponent(res.data), ...staticConfigRoutes] 这里我们将 home 放在菜单的第一个位置上
  5. 根据菜单信息生成路由信息 await setAddRoute();
  6. 保存路信息到pinia中 await setFilterMenuAndCacheTagsViewRoutes();

拦截请求增加token

在使用axios 发送请求时拦截请求信息如果有token 信息则带着token 信息进行请求

service.interceptors.request.use((config: InternalAxiosRequestConfig) => {
    // get查询参数序列化
    if (config.method === 'get') {
        config.paramsSerializer = (params: any) => {
            return qs.stringify(params, { arrayFormat: 'repeat' })
        }
    }
    // 在发送请求之前做些什么 token
    if (Session.get('token')) {
        config.headers!['Authorization'] = `Bearer ${Session.get('token')}`;
    }
    return config;
},
    (error) => {
        // 对请求错误做些什么
        return Promise.reject(error);
    }
);

发送请求之后如果后端返回信息中不是200表明请求有异常针对 424 进行令牌过期提醒,并跳转丁路界面进行重新登录

service.interceptors.response.use((res: any) => {
    if (res.data.code === 1) {
        throw res.data
    }
    return res.data;
}, error => {
    const status = Number(error.response.status) || 200
    const message = error.response.data.msg || errorCode[status] || errorCode['default']
    if (status === 424) {
        ElMessageBox.confirm('令牌状态已过期,请点击重新登录', '系统提示', {
            confirmButtonText: '重新登录',
            cancelButtonText: '取消',
            type: 'warning'
        })
            .then(() => {
                Session.clear(); // 清除浏览器全部临时缓存
                window.location.href = '/'; // 去登录页
                return
            })
            .catch(() => {
            })
    }

    if (status !== 200 || error.response.data.code === 1) {
        ElMessage.error(message)
        return Promise.reject(new Error(message))
    }
    return Promise.reject(error);
})