一、Vue登录逻辑梳理:
1、登录流程:
- 用户在前端输入用户名和密码,点击登录按钮。
登录成功后的逻辑:
主要功能和流程:
异步函数
signInSuccess
:这是一个异步函数,使用了async
关键字,意味着函数内部可能包含异步操作。后端权限控制 :首先调用
initBackEndControlRoutes()
函数来初始化后端控制路由,并等待其返回结果。如果isNoPower
为真(即没有权限),则显示警告消息,清除会话信息(可能是用户信息或令牌等)。登录成功处理:如果有权限,继续执行登录成功后的逻辑。具体包括:
- 初始化当前时间信息并格式化。
- 检查路由中是否有
redirect
参数,如果有则根据参数进行路由跳转,否则跳转到根路径/
。- 显示登录成功提示信息,包括当前时间和登录文本。
- 启动加载状态,可能是为了防止页面首次加载时出现空白或显示加载状态。
路由跳转:根据条件进行路由跳转,可能是根据 URL 中的参数决定跳转目标。
消息提示 :使用
useMessage()
函数来显示不同类型的消息,包括警告和成功消息。加载状态 :使用
NextLoading.start()
来启动加载状态,可能是为了提供更好的用户体验。总体来说,这段代码主要负责处理用户登录成功后的一系列操作,包括权限控制、路由跳转、消息提示和加载状态管理。如果你有任何具体问题或需要进一步解释,请随时告诉我。
全局的加载状态管理功能:
NextLoading
的对象,用于管理页面的全局加载状态。让我来解释一下这段代码的主要功能和结构:
导入依赖 :代码中导入了 Vue 3 中的
nextTick
方法以及一个自定义的样式表loading.scss
。全局 Loading 对象 :
NextLoading
对象包含两方法:
- start() 方法 :用于创建加载状态。在页面中动态创建一个包含加载动画的元素,并插入到页面的顶部,显示加载状态。设置了
window.nextLoading
变量为true
,可能用于全局状态管理。- done(time) 方法 :用于移除加载状态。通过
nextTick
等待页面更新后再执行,可以传入一个延迟时间time
,在延迟后移除加载状态元素,并将window.nextLoading
变量设置为false
。加载元素结构 :
start()
方法中创建的加载状态元素包含了一组加载动画的 HTML 结构,通过设置不同的类名和样式来展示加载效果。动态插入和移除 :在
start()
方法中,将创建的加载状态元素插入到页面的顶部,显示加载状态。在done()
方法中,通过查询元素并移除的方式来隐藏加载状态。全局状态管理 :通过设置
window.nextLoading
变量来记录加载状态,可能在其他地方用于判断页面是否处于加载状态。这段代码的作用是在页面中实现一个全局的加载状态管理功能,通过调用
NextLoading.start()
和NextLoading.done()
方法来显示和隐藏加载状态。这样的实现可以提升用户体验,让用户清晰地知道页面正在加载中。JS:
javascript/** * 页面全局 Loading * @method start 创建 loading * @method done 移除 loading */ const NextLoading = { // 创建 loading start: () => { const bodys = document.body; const div = document.createElement('div'); div.setAttribute('class', 'loading-next'); const htmls = ` <div class="loading-next-box"> <div class="loading-next-box-warp"> <div class="loading-next-box-item"></div> <div class="loading-next-box-item"></div> <div class="loading-next-box-item"></div> <div class="loading-next-box-item"></div> <div class="loading-next-box-item"></div> <div class="loading-next-box-item"></div> <div class="loading-next-box-item"></div> <div class="loading-next-box-item"></div> <div class="loading-next-box-item"></div> </div> </div> `; div.innerHTML = htmls; bodys.insertBefore(div, bodys.childNodes[0]); window.nextLoading = true; }, // 移除 loading done: (time = 0) => { setTimeout(() => { window.nextLoading = false; const el = document.querySelector('.loading-next'); if (el) { el.parentNode.removeChild(el); } }, time); }, };
前端控制路由的初始化方法和相关功能的实现。它主要涉及到前端控制路由的权限管理和动态路由添加。以下是代码的详细介绍:
初始化前端控制路由 :
initFrontEndControlRoutes
方法是用于初始化前端控制路由的方法。它包括界面 loading 动画开始执行、初始化用户信息、添加动态路由以及设置递归过滤有权限的路由到 Pinia 的 routesList 中。添加动态路由 :
setAddRoute
方法用于添加动态路由。它循环处理 baseRoutes 第一个顶级 children 的路由一维数组,并通过router.addRoute
方法添加路由。删除/重置路由 :
frontEndsResetRoute
方法用于删除或重置路由。它也循环处理 baseRoutes 第一个顶级 children 的路由一维数组,并通过router.removeRoute
方法删除路由。过滤有权限的路由 :
setFilterRouteEnd
方法用于获取有当前用户权限标识的路由数组,并进行对原路由的替换。它替换 baseRoutes 第一个顶级 children 的路由,并添加notFoundAndNoPower
路由。缓存多级嵌套数组处理后的一维数组 :
setCacheTagsViewRoutes
方法用于缓存多级嵌套数组处理后的一维数组。它用于 tagsView、菜单搜索中,未过滤隐藏的路由。设置递归过滤有权限的路由 :
setFilterMenuAndCacheTagsViewRoutes
方法用于设置递归过滤有权限的路由到 Pinia 的 routesList 中,并缓存多级嵌套数组处理后的一维数组。判断用户权限 :
hasRoles
方法用于判断路由的meta.roles
中是否包含当前登录用户的权限字段。过滤有权限的路由 :
setFilterHasRolesMenu
方法用于获取当前用户权限标识去比对路由表,设置递归过滤有权限的路由。这些方法共同实现了前端控制路由的权限管理和动态路由添加的功能。
- 前端发送登录请求到后端的登录接口,携带用户名和密码。
- 后端接收请求,验证用户名和密码,验证成功后生成一个 token,并返回给前端。
2.Token 存储:
前端接收到 token 后,将 token 存储到 localStorage 、sessionStorage和 Vuex (pinia)中。
2.1 封装 localStorage
和 sessionStorage:
javascript
import Cookies from "js-cookie";
const Local = {
setKey(key) {
return `${__NEXT_NAME__}:${key}`;
},
set(key, val) {
window.localStorage.setItem(Local.setKey(key), JSON.stringify(val));
},
get(key) {
let json = window.localStorage.getItem(Local.setKey(key));
return JSON.parse(json);
},
remove(key) {
window.localStorage.removeItem(Local.setKey(key));
},
clear() {
window.localStorage.clear();
},
};
const Session = {
set(key, val) {
if (key === 'token' || key === 'refresh_token') {
Cookies.set(key, val);
}
window.sessionStorage.setItem(key, JSON.stringify(val));
},
get(key) {
if (key === 'token' || key === 'refresh_token') return Cookies.get(key);
let json = window.sessionStorage.getItem(key);
return JSON.parse(json);
},
remove(key) {
if (key === 'token' || key === 'refresh_token') return Cookies.remove(key);
window.sessionStorage.removeItem(key);
},
clear() {
Cookies.remove('token');
Cookies.remove('refresh_token');
Cookies.remove('tenantId');
window.sessionStorage.clear();
},
getToken() {
return this.get('token');
},
getTenant() {
return Local.get('tenantId') ? Local.get('tenantId') : 1;
},
};
2.前端在每次路由跳转时,检查 localStorage 中是否存在 token,如果不存在则跳转到登录页面。
3.请求头携带 Token:
- 在每次向后端发送请求时,前端在请求头中加入 token,以便后端验证用户身份。
4.后端验证 Token:
- 后端在接收到请求时,判断请求头中是否携带 token。
- 如果有 token,后端验证 token 的有效性,验证成功则返回数据,验证失败(如 token 过期)则返回 401 状态码。
- 如果请求头中没有 token,则返回 401 状态码。
5.401 状态码处理:
- 前端在接收到 401 状态码时,清除 localStorage 和 Vuex 中的 token 信息。
- 前端跳转到登录页面,提示用户重新登录。
- 可以考虑实现一个 token 刷新机制,尝试使用 refresh token 来获取新的 access token,避免用户频繁登录。