上一篇概述了我在前后端分离认证的处理流程 CAS 认证之前后端分离
本文记录一下前后端分离之后, 前端登录流程, 权限校验, 动态路由等
登录流程简介
- iframe引入CAS登录页(CAS登录url从后端获取)
<iframe id="loginFrame" class="lxb-login-frame-from" :src="iframePath"></iframe>
- 通过特殊的与接口交互接口 /v1/creat-session 交由后端创建 sessionId 并通过 postMessage 传递回登录页
<iframe :src="http://xxxx/v1/creat-session" class="lxb-login-frame-creat-session"></iframe>
- 通过第2步拿到的sessionId建立socket连接
端接口无法确认前端用户, 此处用sessionId保持链接唯一性
window.addEventListener ('message', function (e) {
// 获取从iframe子页面传递的sessionId
});
this.socket = io(constant.loginSocketIo + '?clientId=' + this.sessionId);
this.socket.on('connect', () => {
this.log('connected ');
});
- 登录成功后,通过第3步建立的socket链接接收token
token存入 sessionStorage
改变Vuex中登录状态(状态被改变时, 同时加载系统动态路由部分, 用户信息等)
this.socket.on('messageevent', (data) => {
// 登录成功
sessionStorage.setItem('token', data.msgContent);
this.$store.commit(LOGIN_STATE, true);
this.$router.push('/home');
});
-
跳转页面至首页
-
在路由 beforeEach 中检查用户权限, 初次尝试加载权限, 用户菜单, 校验成功则进入next();
router.beforeEach((to, from, next) => {
iView.LoadingBar.start();
Util.title(to.meta.title);
let userPermis = store.state.permis;
let routerPermis = to.meta.permis;
if (userPermis && routerPermis) {
if (userPermis.includes(routerPermis)) {
// 匹配到权限
next();
} else {
// 没有权限
next({replace: true, name: 'error-403'});
}
} else if (!userPermis && routerPermis && store.state.login) {
// 用户没有权限, 路由需要权限, 尝试加载用户权限
initMenus(() => {
next({ ...to, replace: true });
});
} else {
// 没有配置过权限
next();
}
});
/**
* 加载菜单, 权限
*/
export function initMenus(callback) {
Vue.prototype.get({
url: '/lesp/v1/basic/data/menus',
callback: (v) => {
store.commit(USER_MENUS, v.menus);
store.commit(USER_PERMIS, v.permis);
if (callback) {
callback();
}
}
});
}
退出登录流程
-
创建iframe指向/logout, 先退出服务端
-
iframe加载完成后, 清除 sessionStorge 中的token
-
跳转页面至登陆
this.logoutPath = constant.serverDomain + '/logout';
let iframe = document.getElementById("logoutFrame");
if (iframe.attachEvent) {
iframe.attachEvent("onload", () => this.clearLoginToken());
} else {
iframe.onload = () => this.clearLoginToken();
}
clearLoginToken() {
this.$Modal.remove();
sessionStorage.removeItem('token');
this.$Message.info('退出成功 !');
this.$router.push('/login');
}
权限控制及校验
路由权限控制
-
登录成功, 在 beforeEach 中检查用户权限, 并尝试加载用户权限, 用户菜单, 并重新执行此步骤
- 用户信息 Vuex.state.user
- 权限放入权限池 Vuex.state.permis
- 用户菜单放入菜单池 Vuex.state.menus
按钮, 链接等权限控制
- 通过指令 v-auth:permis="权限标识" 控制
- 指令在 inserted 检查权限池是否存在此权限, 如无权限, 则移除此dom
import store from '../store';
// 权限校验指令
export const haxAuth = {
inserted (el, { value }, vnode) {
// let permis = el.getAttribute('data-permis').trim();
// 无权限, 则移除此dom
if(value && !store.state.permis.includes(value)) {
el.parentNode.removeChild(el);
}
},
componentUpdated (el, { value }) {
},
unbind: function unbind (el, binding) {
}
};
render中写法有所区别, 具体可自行查看文档, 此处只做demo
directives: [
{
name: 'auth',
value: permis,
arg: 'permis'
}
],
菜单权限
-
登录成功即加载用户菜单, 并放入菜单池
-
菜单组件中检测菜单池change, 并渲染页面
路由组装
-
登录成功即加载系统功能, 并组装路由数据放入Vuex.state.routers
-
watch Vuex.state.routers, 并填入路由中
this.$router.addRoutes();
至此完成了CAS认证登录, 对菜单, 按钮, 链接, 展示文本等做了鉴权, 并实现了动态路由, 由权限控制路由.
本文由 anybbo 创作,采用 知识共享署名4.0
国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Dec 17,2020