这里大致说一下开发过程中经常用到的配置
config/dev.env.js
这里是开发过程中需要修改的一个地方
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
BASE_API: '"http://localhost:8443"', // 访问后端用到的基础地址,在src/utile/request中用到
})
config/index.js
这里大部分是webpack的基础配置一般不需要修改
host: 'localhost',
port: 9527, // 前端服务器端口
autoOpenBrowser: true, // 运行时自动打开浏览器
errorOverlay: true,// 当编译器错误时在浏览器上显示全屏报错
useEslint: true // 使用eslint
config/index.js 中 build 下有一个 assetsRoot 这里表示了打包时输出的位置
assetsRoot: path.resolve(__dirname, '../dist'),
在 build/webpack.base.conf.js 中 output 下的 path 中有引用 assetsRoot 设置输出路径
entry: {
app: './src/main.js' // 设置了webpack 入口文件为main.js
},
以上的配置大部分在 build/webpack.base.conf.js 中使用,有兴趣深入了解的可以结合webpack官方文档了解。
首先首页和登陆功能是如何实现的?
首先请看 src/views/login/index.vue 这个是框架的登录页面
注意一下 handleLogin 方法里面有这么一句
// 调用 store 中的 aciton 方法访问后端,成功则将路由跳转到 / 也就是主页
this.$store.dispatch('LoginByUsername', this.loginForm).then(() => {
this.loading = false
this.$router.push({ path: this.redirect || '/' })
}).catch(() => {
this.loading = false
})
现在我们来看一下 store 中的 login 方法是怎么写的
src/store/modles/user.js
这里访问后端接口进行登录,成功返回 token 并保存到 store 和 cookie 中,然后执行上面的 this.$router.push({ path: this.redirect || ‘/’ }) 跳转路由到首页
失败则返回失败信息
// 用户名登录
LoginByUsername({ commit }, userInfo) {
const username = userInfo.username.trim()
return new Promise((resolve, reject) => {
loginByUsername(username, userInfo.password).then(response => {
const data = response.data
// 登陆成功后将后端返回的 token 保存到 store 和 cookie 中
commit('SET_TOKEN', data.token)
setToken(response.data.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
登陆成功后,在跳转主页之前会执行 src/permission.js 里定义的路由的全局前置守卫 beforeEach
src/permission.js
router.beforeEach((to, from, next) => {
NProgress.start() // NProgress 是一个进度条组件(在页面上方一个蓝色的进度条),这里表示启动进度条
if (getToken()) { // 通过 getToken 方法从 cookie 中获取 token ,如果不存在则重定向到登录页
/* 存在token */
if (to.path === '/login') { //如果是登陆页,就重定向到主页
next({ path: '/' })
NProgress.done() // 进度条组件结束
} else {
// 当访问主页时,会执行下面这段逻辑获取用户权限信息
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
store.dispatch('GetUserInfo').then(res => { // 访问后台拉取user_info
const roles = res.data.roles // note: roles must be a array! such as: ['editor','develop']
store.dispatch('GenerateRoutes', { roles }).then(() => { // 根据roles权限生成可访问的路由表
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
})
}).catch((err) => {
store.dispatch('FedLogOut').then(() => {
Message.error(err)
next({ path: '/' })
})
})
} else {
// 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
if (hasPermission(store.getters.roles, to.meta.roles)) {
next()
} else {
next({ path: '/401', replace: true, query: { noGoBack: true }})
}
// 可删 ↑
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
next()
} else {
next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页
NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
}
}
})
请注意这里 store.dispatch(‘GenerateRoutes’, { roles }).then(()
这里调用了 src/store/modules/permission.js 中的 GenerateRoutes 来进行权限判断,大致逻辑是如果用户的角色包含 admin 就返回全部的动态路由。不包含 admin ,则调用 filterAsyncRouter 递归判断角色是否有路由的权限。具体判断代码在hasPermission中
/**
* 通过meta.role判断是否与当前用户权限匹配
* @param roles
* @param route
*/
function (roles, route) {
if (route.meta && route.meta.roles) {
return roles.some(role => route.meta.roles.includes(role)) // 这里判断了路由的.meta.roles 属性中是否包含 role
} else {
return true
}
}
到这里就可以看一下路由究竟是怎么写的了
这里 asyncRouterMap 动态路由中都有一个 roles 属性,用于判断用户权限。
同时注意一下主页的路由,登陆成功后有这么一句重定向 this.$router.push({ path: this.redirect || ‘/’ }) 会触发下面的路由访问主页
{
path: '',
component: Layout,
redirect: 'dashboard',
children: [
{
path: 'dashboard',
component: () => import('@/views/dashboard/index'),
name: 'Dashboard',
meta: { title: 'dashboard', icon: 'dashboard', noCache: true, affix: true }
}
]
},