将权限管理应用到系统,首先做好登录, 点击登录按钮后,触发以下动作

  • vuex 中的 login 动作,设置 cookie
  • vuex 中的 getuserinfo , 获取权限、用户名、头像等

    由于目前未使用连接后端服务器,所以使用 mockjs 拦截请求并返回。

    github中查看

1 全局请求拦截

使用axios 封装好请求和响应

src/utils/request.js

import axios from 'axios'

const clearRequest = {
source: {
token: null,
cancel: null
}
}
const cancelToken = axios.CancelToken
const source = cancelToken.source() // 创建 axios 实例
const service = axios.create({
cancelToken: source.token,
timeout: 6000, // 请求超时时间
}) // request 拦截器
service.interceptors.request.use(
config => {
config.cancelToken = clearRequest.source.token
return config
},
error => {
return Promise.reject(error)
}
) // response 拦截器
service.interceptors.response.use(
resp => resp,
error => {
return Promise.reject(error)
}
) export { clearRequest }
export default service

2 封装一些常用的函数

src/utils/index.js

export function param2Obj(url){
const search = url.split('?')[1]
if(!search){
return {}
}
return JSON.parse(
'{"' +
decodeURIComponent(search)
.replace(/"/g, '\\"')
.replace(/&/g, '","')
.replace(/=/g, '":"') +
'"}'
)
}

src/utils/auth.js

import Cookies from 'js-cookie'

const tokenKey = 'X-Token'

export function getToken(){
return Cookies.get(tokenKey)
} export function setToken(token){
return Cookies.set(tokenKey, token)
} export function removeToken(){
return Cookies.remove(tokenKey)
}

3 编写登录api

src/api/login.js 文件

import request from '@/utils/request'

export function loginByUsernameApi(username, password){
return request({
url: '/api/auth/api-token-auth',
method: 'post',
data: {
username,
password
}
})
} export function getUserInfoApi(token){
return request({
url: '/api/userinfo',
method: 'get',
params: {token}
})
} export function logoutApi(){
return request({
url: '/api/auth/logout',
method: 'post'
})
}

4 mock 拦截

src/mock/index.js

import Mock from 'mockjs'
import login from './login' // 登录相关
Mock.mock(/\/api\/auth\/api-token-auth/, 'post', login.loginByUsername)
Mock.mock(/\/api\/auth\/logout/, 'post', login.logout)
Mock.mock(/\/api\/userinfo/, 'get', login.getUserInfo) export default Mock

src/mock/login.js

import { param2Obj } from '@/utils'

const usermap = {
admin: {
token: 'admin',
introduction: '我是超级管理员',
name: 'Super Admin',
pass: 'e10adc3949ba59abbe56e057f20f883e',
roles: ['admin']
},
developer: {
token: 'developer',
introduction: '我是开发',
name: '工程师小王',
pass: 'e10adc3949ba59abbe56e057f20f883e',
roles: ['/system', '/system/permit', '/system/permit/account']
}
} export default {
loginByUsername: config => {
const { username, password } = JSON.parse(config.body)
console.log('loginByUsername username, password: ', username, password)
if(username === 'admin'){
if(usermap[username].pass === password){
return usermap['admin']
}else{
return []
}
}
return usermap[username]
},
getUserInfo: config => {
console.log('getUserInfo config: ', config)
const { token } = param2Obj(config.url)
let tok = false
for(let key in usermap){
if(token.indexOf(usermap[key].token) !== -1){
tok = usermap[key]
break;
}
}
return tok },
logout: () => 'success'
}

5 vuex 的使用

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
import permission from './modules/permissions'
import getters from './getters' Vue.use(Vuex) const store = new Vuex.Store({
modules: {
permission,
user,
},
getters
})
export default store

src/store/modules/user.js

import { loginByUsernameApi, logoutApi, getUserInfoApi } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth' const user = {
state: {
token: getToken(),
name: '',
avatar: '',
roles: []
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_NAME: ( state, name) => {
state.name = name
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_ROLES: (state, roles) => {
state.roles = roles
}
},
actions: {
// 登入
LoginByUsername({commit}, userinfo){
const username = userinfo.username.trim()
return new Promise((resolve, reject) => {
loginByUsernameApi(username, userinfo.password)
.then(resp => {
const data = resp.data
setToken(data.token)
console.log('in LoginByUsername, setToken: ', data.token)
commit('SET_TOKEN', data.token)
resolve()
})
.catch(err => {
reject(err)
})
})
},
// 获取用户权限等
GetUserInfo({commit, state}) {
console.log('in GetUserInfo')
return new Promise((resolve, reject) => {
getUserInfoApi(state.token)
.then(resp => {
if(!resp.data){
reject('error')
}
const data = resp.data
if(data.roles && data.roles.length){
commit('SET_ROLES', data.roles)
}else {
reject('getUserInfoApi: roles must be a non-null array!')
}
if(data.name){
commit('SET_NAME', data.name)
}
if(data.avatar){
commit('SET_AVATAR', data.avatar)
}
resolve(resp)
})
.catch(err => {
reject(err)
})
})
},
// 登出
LogOut({commit, state}){
return new Promise((resolve, reject) => {
logoutApi(state.token)
.then(() => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
resolve()
})
.catch(err => {
reject(err)
})
})
},
// 前端登出
FedLogOut({commit}){
return new Promise(resolve => {
commit('SET_TOKEN', '')
removeToken()
resolve()
})
}
}
} export default user

src/store/modules/permissions.js

import { asyncRouterMap, constantRouterMap } from '@/router'

/**
* 通过 meta.role 判断是否与当前用户权限匹配
*/
function hasRoles (roles, route){
if(route.meta && route.meta.roles){
return roles.some(role => route.meta.roles.includes(role))
}else{
return true
}
} /**
* 递归过滤异步路由表,返回符合用户角色权限的路由表
*/
function filterAsyncRouter(asyncRouterMap, roles){
const accessedRouters = asyncRouterMap.filter(route => {
// 404
if(route.path === '*'){
return true
}else if(hasRoles(roles, route)){
if(route.children && route.children.length){
route.children = filterAsyncRouter(route.children, roles)
}
return true
}
return false
})
return accessedRouters
} // 在有权限的路由表里,查找是否有到目标path的路由
// 为了保持路由唯一性,拼接父子路由
function hasDestRoute (froute, permitRouterMap, to) {
let r = froute === '/' ? '' : froute
return permitRouterMap.some(route => {
let path = r + '/' + route.path
if (to.path.indexOf(path) !== -1) {
return true;
}
if (route.children && route.children.length) { //如果有孩子就遍历孩子
return hasDestRoute(path, route.children, to)
}
})
} const permission = {
state: {
routers: constantRouterMap,
addRouters: [],
sidebar_routers: {},
},
mutations: {
SET_ROUTERS: (state, routers) => {
state.addRouters = routers,
state.routers = constantRouterMap.concat(routers)
},
SET_NOW_ROUTERS: (state, to) => {
console.log('in SET_NOW_ROUTERS')
// 由于首页重定向到 /dashboard,并且不参与权限控制,特殊处理
if(to.path === '/dashboard'){
let dashboard = state.routers.filter(v => v.path === '/' )
state.sidebar_routers = dashboard[0]
}else{
// 递归访问 accessedRouters,找到包含to 的那个路由对象,设置给 sidebar_routers
state.addRouters.forEach(e => {
if (e.children && e.children.length) {
if ( hasDestRoute(e.path, e.children, to)){
if(state.sidebar_routers.path){
// 存在 sidebar_routers 且与目标路由不同
if(state.sidebar_routers.path !== e.path){
state.sidebar_routers = e;
}
}else{
state.sidebar_routers = e;
}
}
}
})
}
}
},
actions: {
GenerateRoutes({commit}, data) {
console.log('in GenerateRoutes')
return new Promise(resolve => {
const {roles} = data
let accessedRouters
if(roles.includes('admin')){
accessedRouters = asyncRouterMap
}else{
accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
}
commit('SET_ROUTERS', accessedRouters)
resolve()
})
},
GenSidebarRoutes({commit}, data) {
console.log('in GenSidebarRoutes')
return new Promise(resolve => {
commit('SET_NOW_ROUTERS', data)
resolve()
})
}
}
} export default permission

src/store/getters.js

const getters = {
token: state => state.user.token,
roles: state => state.user.roles,
avatar: state => state.user.avatar,
name: state => state.user.name,
addRouters: state => state.permission.addRouters,
permission_routers: state => state.permission.routers,
sidebar_routers: state => state.permission.sidebar_routers,
} export default getters

6 修改 login 页面

src/views/TheLogin.vue

handleSubmit(event) {
this.$refs.ruleForm2.validate((valid) => {
if (valid) {
this.logining = true;
// 触发 vuex 中 LoginByUsername 事件
const username = this.ruleForm2.username
let password = md5(this.ruleForm2.password)
if(this.hidePassword !== '' && this.ruleForm2.password === '********'){
password = this.hidePassword
}
this.$store.dispatch('LoginByUsername', {'username': username, 'password': password})
.then(() => {
this.logining = false
if(this.rememberme){
this.setCookie(this.ruleForm2.username, password, 7)
}else{
this.clearCookie()
}
// 重定向到首页
this.$router.push({ path: this.redirect || '/' })
})
.catch(err => {
this.logining = false
this.$alert(err, {
type: 'warning',
confirmButtonText: 'ok'
})
})
} else {
console.log('error submit!');
return false;
}
})
}

7 修改main 主入口

src/main.js

/** ...*/
import store from './store'
import '@/login'
import '@/mock' Vue.use(ElementUI)
Vue.config.productionTip = false /* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})

8 关键的权限控制

src/login.js

import router from './router'
import NProgress from 'nprogress'
import {clearRequest} from '@/utils/request'
import axios from 'axios'
import store from './store' function hasPermission(roles, permissionRoles){
if(roles.indexOf('admin') >= 0){
return true // admin 权限 直接通过
}
// 没有配置权限的菜单直接进入
if(! permissionRoles){
return true
}
return roles.some(role => permissionRoles.indexOf(role) >= 0)
} const whiteList = ['/login', ] // 不重定向白名单
router.beforeEach((to, from, next) => {
console.log('to.path: ' + to.path)
console.log('store.getters.token: ' + store.getters.token)
// 切换路由时清空上个路由未完成的所有请求
const cancelToken = axios.CancelToken
clearRequest.source.cancel && clearRequest.source.cancel()
clearRequest.source = cancelToken.source() if(whiteList.indexOf(to.path) !== -1){
next()
}else{
if(store.getters.token){
if(to.path === '/login'){
next({path: '/'})
NProgress.done()
}else{
// 拉取用户信息
if(store.getters.roles.length === 0){
store.dispatch('GetUserInfo')
.then(resp => {
const roles = resp.data.roles
console.log('roles: ', roles)
// 根据权限生成可访问的路由表
store.dispatch('GenerateRoutes', {roles})
.then(() => {
// 动态添加路由表
router.addRoutes(store.getters.addRouters)
next({...to, replace: true}) // 确保 addRouters 已完成
})
})
.catch(err => {
store.dispatch('FedLogOut')
.then(() => {
console.log('认证失败,请重新登陆')
next({path: '/login'})
})
})
}else{
console.log('call GenSidebarRoutes')
store.dispatch('GenSidebarRoutes', to)
.then(() => {
if(hasPermission(store.getters.roles, to.meta.role)){
next()
}else{
next({path: '/', query: {noGoBack: true}})
}
})
}
}
}else{
// 重定向到 /login
next({path: '/login', query: {redirect: to.fullpath}})
NProgress.done()
}
}
}) router.afterEach(() => {
NProgress.done()
})

目录结构

│  App.vue
│ login.js
│ main.js
├─api
│ login.js
│ system.js
├─assets
│ logo.png
├─components
│ HelloWorld.vue
│ Navbar.vue
│ NavbarItem.vue
│ Sidebar.vue
│ SidebarItem.vue
├─containers
│ Container.vue
├─mock
│ article.js
│ index.js
│ login.js
│ system.js
├─router
│ │ index.js
│ │
│ └─modules
│ system.js
├─store
│ │ getters.js
│ │ index.js
│ │
│ └─modules
│ permissions.js
│ user.js
├─styles
│ animate.scss
│ browser-prefix.scss
│ index.scss
├─utils
│ auth.js
│ index.js
│ request.js
└─views
│ 404.vue
│ Home.vue
│ TheLogin.vue
├─article
│ index.vue
├─dashboard
│ index.vue
├─SidebarMenu
│ index.vue
└─system
└─permit
│ account.vue
│ accountgroup.vue
│ authorize.vue
│ index.vue
│ role.vue
└─components
DialogRoleMenu.vue

admin 用户权限:

developer 权限:

vue+elementui搭建后台管理界面(7 vuex和mockjs的使用)的更多相关文章

  1. vue+elementui搭建后台管理界面(6登录和菜单权限控制)

    不同的权限对应不同的路由(菜单),同时侧边栏也根据权限异步生成,实现登录和鉴权思路如下: 登录:点击登录,服务器验证通过后返回一个 token ,然后存到 cookie,再根据 token 拉取用户权 ...

  2. vue+elementui搭建后台管理界面(2首页)

    1 会话存储 使用html5的 sessionStorage 对象临时保存会话 // 保存会话 sessionStorage.setItem('user', username) // 删除会话 ses ...

  3. vue+elementui搭建后台管理界面

    1 会话存储 使用html5的 sessionStorage 对象临时保存会话 // 保存会话 sessionStorage.setItem('user', username) // 删除会话 ses ...

  4. vue+elementui搭建后台管理界面(1登录)

    1 node环境安装 从 node官网下载安装包 2 vue-cli npm install vue-cli -g 3 新建项目 vue init webpack vue-project 可保持默认, ...

  5. vue+elementui搭建后台管理界面(8 同步/异步获取数据渲染table)

    elementui已经封装好了 el-table 组件,只需要指定 data 数据源即可,因此通常在 vue 实例生命周期的 created 阶段,从数据库获取数据,再将返回的数据绑定到 data 如 ...

  6. vue+elementui搭建后台管理界面(5递归生成侧栏路由)

    有一个菜单树,顶层菜单下面有多个子菜单,子菜单下还有子菜单... 这时候就要用递归处理 1 定义多级菜单 修改 src/router/index.js 的 / 路由 { path: '/', redi ...

  7. vue+elementui搭建后台管理界面(3侧边栏菜单)

    上一节搭好了主框架,但是标签页和侧边栏只是分别展示了各自的菜单,如何将二者联动起来? 定义路由规则:当有 children 属性时,从 children 里取出 path 填充到侧边栏,如: { pa ...

  8. vue+elementui搭建后台管理界面(6登录和菜单权限控制[二])

    根据权限计算路由的代码 /** * 通过meta.role判断是否与当前用户权限匹配 * @param roles * @param route */ function hasRoles (roles ...

  9. vue+elementui搭建后台管理界面(4使用font-awesome)

    使用font-awesome npm install --save font-awesome 修改 src/main.js 增加 import 'font-awesome/scss/font-awes ...

随机推荐

  1. JAVA基础之HttpServletRequest请求

    HttpServletRequest请求是获取请求行.请求头和请求体:可以通过这个方法设置防盗链,获取地址.牢记解决乱码的方式. 怎么选择是重定向还是转发呢?通常情况下转发更快,而且能保持reques ...

  2. 激活windows去掉右下角水印

     激活windows去掉右下角水印 //需要隔一段时间执行一次 // 卸载已有的激活产品slmgr.vbs /upk // 重新按照激活产品slmgr /ipk NPPR9-FWDCX-D2C8J-H ...

  3. Java JAR包

    JAR文件全称 Java Archive File,意为Java档案文件.JAR文件是一种压缩文件,也被成为JAR包. 运行程序时,JVM会自动在内存中解压要用的JAR包. 使用JAR包的优点:1.安 ...

  4. 深入理解jvm--性能监控工具

    1.jvm监控工具介绍 1.1.jconsole JConsole是一个基于JMX的GUI工具,用于连接正在运行的JVM,不过此JVM需要使用可管理的模式启动. 1.2.启动jconsole 通过JD ...

  5. 【RAC】 RAC For W2K8R2 安装--RDBMS软件的安装(五)

    [RAC] RAC For W2K8R2 安装--RDBMS软件的安装(五) 一.1  BLOG文档结构图 一.2  前言部分 一.2.1  导读 各位技术爱好者,看完本文后,你可以掌握如下的技能,也 ...

  6. selenium获取元素

    1.获取窗口titledriver.title2.获取urldriver.current_url3.获取窗口截图driver.get_screenshot_as_file('window.png')4 ...

  7. python测试开发django-43.xadmin添加小组件报错解决

    前言 xadmin首页上有个添加小组件按钮,打开的时候会报错“render() got an unexpected keyword argument 'renderer'”环境:python3.6dj ...

  8. Linux命令——mknode

    参考:What is the mknod command used for? 前言 Linux下面,一切皆文件,当然也包括设备.Linux通过major.minor号来区分不同设备,如下图

  9. 19.centos7基础学习与积累-005-命令总结01

    从头开始积累centos7系统运用 大牛博客:https://blog.51cto.com/yangrong/p5 1.查看命令帮助的方法: --help 适用于一般命令,非内置命令 man  适用于 ...

  10. thinkphp5.x命令执行漏洞复现及环境搭建

    楼主Linux环境是Centos7,LAMP怎么搭不用我废话吧,别看错了 一.thinkphp5.X系列 1.安装composer yum -y install composer 安装php拓展 yu ...