一:框架介绍**
vue-element-admin 是一个后台前端解决方案,它基于 vue 和 element-ui实现。它使用了最新的前端技术栈,内置了 i18 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件。
集成方案: vue-element-admin
基础模板: vue-admin-template
二:环境准备
需要在本地安装 node 和 git。本项目技术栈基于 ES2015+、vue、vuex、vue-router 、vue-cli 、axios 和 element-ui,所有的请求数据都使用Mock.js进行模拟。不支持低版本浏览器(如 ie)
三:目录结构
下面是整个项目的目录结构。
补充:
1、public下index.html 时一个模板文件,作用是生成项目的入口文件,webpack打包的js,css也会注入到该页面中。浏览器访问项目的时候就会默认打开生成好的index.html
四:安装
# 克隆项目
git clone https://github.com/PanJiaChen/vue-element-admin.git
# 进入项目目录
cd vue-element-admin
# 安装依赖
npm install
# 建议不要用 cnpm 安装 会有各种诡异的bug 可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npm.taobao.org
# 本地开发 启动项目
npm run dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
启动完成后会自动打开浏览器访问 http://localhost:9527, 你看到下面的页面就代表操作成功了。
五:登录及权限
登录逻辑:当用户填写完账号密码后向服务端验证是否正确,验证通过后,服务端会返回一个token,拿到token后(可将token存到cookie中,保证页面刷新后可以记住用户登录状态),前端会根据token拉取一个 user_info接口来获取用户详情信息(如用户权限,用户名等)。
权限验证:通过token获取用户对应的 role,动态根据用户的 role 算出其对应有权限的路由,通过 router.addRoutes 动态挂载这些路由。
首先看一下登录的具体流程:
//登录
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.$store.dispatch('user/login', this.loginForm)
.then(() => {
this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
this.loading = false
})
.catch(() => {
this.loading = false
})
} else {
console.log('error submit!!')
return false
}
})
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
可以看出,点击过登录按钮后,调用了$store里的一个方法,名叫login
2、store里面的login方法
// user login
login({commit}, userInfo) {
const {username, password} = userInfo
return new Promise((resolve, reject) => {
login({loginName: username.trim(), passwd: password}).then(response => {
const data = response
commit('SET_TOKEN', data)
setToken(data)
resolve()
}).catch(error => {
reject(error)
})
})
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
此处第一个login是$store中的方法,第二个login方法是,api里的login方法,用来调用接口的
3、api中的login方法
import request from '@/utils/request'
export function login(data) {
return request({
url: uapPath + '/user/launcher',
method: 'post',
data
})
}
1
2
3
4
5
6
7
8
9
此处是api中的login方法,上面import引入了utils下的request,本质上是它调用了request.js,request.js是对axios进行了封装(统一请求拦截和响应拦截),用来请求后台接口的,如果这个接口请求成功,则回到login.vue页面中的.then()方法路由跳转到登录页。
4、request.js
可以看到在这个请求中配置了baseURL,这个值是读取的项目根目录下的.env.development(开发环境)或者.evn.production(生产环境)文件中配置的VUE_APP_BASE_API值。
5、权限控制
permission主要负责全局路由守卫和登录判断,可以理解为一个拦截器,下面来看一下具体的逻辑:
每一步都添加了注释
从代码上来看,主要分两种情况:有token和无token
有token:再看看是不是去登录页的,登录页肯定不能拦截的,如果是登录页就直接放行。如果不是登录页,就要看看本地有没有用户信息,看看cookie中有没有用户信息(不一定是token,也可能是localstorage)。如果有用户信息,放行。如果没有用户信息,就调用接口去获取登录信息,router.addRoutes涉及到了动态添加路由。获取到用户信息后放行。如果在获取用户信息的过程中报错,则回到登录页。
无token:先看看用户要进入的页面是不是在白名单内,一般登录、注册、忘记密码都是在白名单内的,这些页面,在无token的情况下也是直接放行。如果不在白名单内,则回到登录页。
首先说一下element-admin这个框架实现方式:他是通过获取当前用户的权限去比对路由表,生成当前用户具的权限可访问的路由表,通过 router.addRoutes 动态挂载到 router 上。在前端控制权限。
但其实很多公司的业务逻辑可能不是这样的,举一个例子来说,很多公司的需求是每个页面的权限是动态配置的,不像本项目中是写死预设的。但其实原理是相同的。如:你可以在后台通过一个 tree 控件或者其它展现形式给每一个页面动态配置权限,之后将这份路由表存储到后端。当用户登录后得到 roles,前端根据roles 去向后端请求可访问的路由表,从而动态生成可访问页面,之后就是 router.addRoutes 动态挂载到 router 上,你会发现原来是相同的,万变不离其宗。
只是多了一步将后端返回路由表和本地的组件映射到一起。
const map={
login:require('login/index').default // 同步的方式
login:()=>import('login/index') // 异步的方式
}
//你存在服务端的map类似于
const serviceMap=[
{ path: '/login', component: 'login', hidden: true }
]
//之后遍历这个map,动态生成asyncRoutes
并将 component 替换为 map[component]
1
2
3
4
5
6
7
8
9
10
router/index.js
注意这个routes中分两块路由配置
一块是固定的,无权限的路由配置,第二块是,带权限的路由配置,根据用户权限来显示侧边栏。
上面的componentsMap其实就是一个动态需要根据权限加载的路由表。
首先要了解一下,侧边栏是如何渲染出来的,看看layout/components/slibar/index.vue有这样一段代码:
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
1
注意:
mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性
这个permission_routes其实就是路由的元信息,是一个数组
我们在获取用户信息的时候,会得到这个用户所拥有的角色,根据角色来筛选出符合的动态添加的路由,也就是上面permission.js中
routes其实就是上面的两个权限组成的数组,然后传入了GenerateRoutes方法内,我们看下store/permission/generateRoutes中的代码:
首先从@/router/index引入了constantRoutes, componentsMap
可以看出,GenerateRoutes方法中,把从后台获取的菜单list转为tree的格式(其实这块可以在后台根据parentId递归查询即可),由于转为的tree为不可直接用的路由表,必须在把tree数据结构转换为可用的路由格式,存到vuex中。这里我是先给前台组件写在一个map里,key就是路由名称,遍历生成路由的时候,按key取出来组件,后台返回来路由名称后,去这个map里匹配,比如routeMap[‘user’]。
总结:这里就是把原有的获取路由组件逻辑改了一下下,从原来route/index改成异步从后台拿,从后台拿过来之后,在组合成组件。
然后调用了这两句
router.addRoutes(store.getters.addRouters); // 动态添加可访问路由表
router.options.routes=store.getters.routers;
1
2
router.addRoutes()方法是,动态添加路由配置,参数是符合路由配置的数组,然后将路由元信息,变成合并后的路由元信息,因为渲染侧边栏需要用到!
————————————————
版权声明:本文为CSDN博主「刻苦的樊同学」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44001965/article/details/110225388
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。