preface
First of all, thank you for your great praise, your support is my motivation! I wrote one last weekBuild the Element background frame from 0 to 1, a lot of children shoes comments mentioned permission issues, this week I will give you up.GitHub
1. JWT Authorization
At present, most projects adopt JWT authorization authentication, which is also the token login identity verification mechanism we are familiar with. JWT has many benefits. Because JWT is generated by the server, the server will verify the security and effectiveness after the middleman changes the key string. It usually stays in the Authorization header of the request. The front-end children usually obtain tokens and store them through VUEX, and then the data is stored in the session persistently.
Route redirect verifies the token
First, verify whether vuEX stores a token during route redirection. If no token is stored, jump to the login page to obtain the token.
if(to.path ! = ='/login' && !store.state.token) {
next('/login')
NProgress.done() / / end of Progress
} else {
next();
}
Copy the code
Request interception carries a token
After the token exists locally in router.js, we need to bring the token each time we request the interface to verify the validity of the token.
// Intercept before request
if (store.state.token) {
config.headers["Authorization"] = "Bearer " + store.state.token;
}
Copy the code
If the token is not valid, the global error is handled and the login page is directly jumped
case 401:
messages("warning"."User login expired, please log in again.");
store.commit('COMMIT_TOKEN'.' ')
setTimeout((a)= > {
router.replace({
path: "/login".query: {
redirect: router.currentRoute.fullPath
}
});
}, 1000);
break;
Copy the code
See request.js in the project for more code
2. Menu permissions
In this project, I mainly judge the display and hiding of navigation menu by the role type passed from the back end. Roles =[‘admin’] and roles=[‘user’]. Next, I designed a menu table and a routing table. The routing table is mainly used to register routes without considering hierarchy. The menu table needs to consider the hierarchy, which can configure the main menu, sub-menu, icon and a series of things, of course, the menu table is best through the interface data from the back end. Note that there is a meta configuration item in both the menu table and the routing table. It can configure our role permissions. The role permissions of the menu table corresponding to the routing table must be consistent. Menus that do not have role permissions are open by default.
menu.js
{
icon: "el-icon-question".index: "premission".title: "Permission Tests".subs: [{
index: "permission".title: "Menu test".meta: {
roles: ['admin']}}, {index: "permissionBtn".title: "Button Permissions",]}}Copy the code
router.js
{
path: '/permission'.component: getComponent('permission'.'permission'),
meta: {
title: 'Menu Permissions'.roles: ['admin']}},Copy the code
Filter menus by role
Now we start writing the menu logic, go Aside. Vue, first filter the menu table menu.js by role
/** * @param {Arrary} menus * @param {Arrary} roles * @return {Arrary} res filtered menu */
filterMenus(menus, roles) {
const res = [];
menus.forEach(route= > {
consttmp = { ... route };//hasPermission Checks whether permissions match
if (this.hasPermission(roles, tmp)) {
if (tmp.subs) {
tmp.subs = this.filterMenus(tmp.subs, roles); } res.push(tmp); }});return res;
},
Copy the code
/** * Check whether meta. Role matches the current user's permission * @roles * @param menu */
hasPermission(roles, menu) {
if (menu.meta && menu.meta.roles) {
return roles.some(role= > menu.meta.roles.includes(role));
} else {
return true; }},Copy the code
Filter results
computed: {
items() {
let items = this.filterMenus(menu, this.$store.state.roles);
returnitems; }},Copy the code
So far, the permission control is basically complete, but in the process of running the project, there is also a bug. In this project, there is a tagList, which is the open navigation TAB. When the user switches from admin to user, the navigation TAB remains, which means that the user can access the Premission page through the navigation TAB. At this point, I directly through route interception to deal with this situation.
if(to.meta.roles){ to.meta.roles.includes(... store.getters.roles)? next():next('/ 404')}else{
next();
}
Copy the code
All pages without permission will go to 404 page.
3. Button permission control
Button level permissions, to be honest, are generally controlled through the data interface to show, click, and so on. If light has a front end to control it is definitely not a viable option. Project button permissions to register global custom directives to do. First, create a directive folder under SRC to register global directives. Create a new premissionbtn.js folder. Consult the official documentation if you are not familiar with custom directives.
Global directives
import Vue from 'vue'
import store from '@/store/store'
// Register a V-allowed directive
Vue.directive('allowed', {
inserted: function (el, bingding) {
let roles = store.getters.roles
// Determine permissions
if (Array.isArray(roles) && roles.length > 0) {
let allow = bingding.value.some(item= > {
return roles.includes(item)
})
if(! allow) {if (el.parentNode) {
el.parentNode.removeChild(el)
}
}
}
}
})
Copy the code
reference
import './directive/premissionBtn'
Copy the code
So how do custom directives work?
<div class="premissionBtn">
<el-button type="primary" v-allowed="['admin']">I am only admin when the display</el-button>
<br>
<el-button type="info" v-allowed="['user']">I can only show it when I'm a user</el-button>
<br>
<el-button type="warning" v-allowed="['admin','user']">Only if I am admin or user</el-button>
<br>
<el-button type="danger">Any role can be displayed</el-button>
</div>
Copy the code
Afterword.
There are still many areas to be improved and optimized in this project. If there are any deficiencies or better methods in the project, please timely propose them for easy correction. Thank you.
Build the Element framework from 0 to 1