一、导航钩子
1.记录用户登录没,之前是将用户登录信息放到session中,在过滤器中去看用户登录没。现在不行,要使用
vue-router 提供的导航钩子主要用来拦截导航,让它完成跳转或取消。其实就是和java的过滤器一个原理。
导航钩子函数:router.beforeEach ( )
一般用来做一些进入页面的限制。比如没有登录,就不能进入某些页面,只有登录了之后才有权限查看某些页面。。说白了就是路由拦截。
说明:实现用户访问某个vue组件需要登录才能访问,实现步骤如下:
1 在vue-cli的路由配置index.js里给某个vue组件设置 meta:{"isLogin":true} 配置,子路由也要配置isLogin’ 是自定义建名,代码如下:
{
path: '/index', //首页
name: 'index',
meta:{"isLogin":true}, //访问这个页面,需要登录才能访问
redirect:"/welcome",//默认打开index页面,子路由地址指向的地址
component: index,
children:[ //配置子路由
{
path: "/welcome",
name: 'welcome',
meta:{"isLogin":true},
component: welcome
}
],
},
2 在入门文件main.js文件,添加导航钩子函数,配置权限过滤。此导航钩子和java过滤器类似,访问任意vue组件都先访问这个函数,所以在这里可以写用户访问控制逻辑,代码如下
/* 定义一个导航钩子函数
to:到达的下一个路由对象
from:从那个路由来的路由对象
next:相当于java的放行函数,next("/index");
*/
router.beforeEach(function(to,from,next){
//会拦截所有的地址
var name = localStorage.getItem("userName");
//拦截逻辑
//判断到达的路由对象meta值是否需要访问
if(to.meta.isLogin){
//判断是否登录过
if(name != null){
//登陆过,放行
next();
}else{
//没有登录回到登录页面
return next("/login");
}
}else{
//没有配置,放行
next();
}
})
二、权限控制
<!-- router 开启路由地址配置-->
<el-menu
:default-openeds="['1','2']"
text-color="white"
background-color="#333333"
router>
<!-- 一级菜单-->
<!-- index 菜单索引-->
<template v-for="x in node ">
<el-submenu :index="x.index">
<template slot="title">
<i :class="x.icon"></i>
<span>{
{x.name}}</span>
</template>
<!-- 二级菜单-->
<template v-if="x.children!=null">
<template v-for="y in x.children">
<!-- index 路由地址-->
<el-menu-item :index="y.url">
<template>
<i :class="y.icon"></i>
{
{y.name}}
</template>
</el-menu-item>
</template>
</template>
</el-submenu>
</template>
</el-menu>
说明:实现用户根据角色不同,在登录系统主页面看到的权限连接也不同
1 数据库准备,创建用户表,角色表,权限表,用户角色中间表,角色权限中间表,表结构如下:
#用户表
DROP TABLE IF EXISTS `user_info`;
CREATE TABLE `user_info` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(25) DEFAULT NULL,
`user_pwd` varchar(100) DEFAULT NULL,
`user_salt` varchar(100) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
#角色表
DROP TABLE IF EXISTS `role_info`;
CREATE TABLE `role_info` (
`role_id` int(11) NOT NULL AUTO_INCREMENT,
`role_name` varchar(28) DEFAULT NULL,
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
#权限表
DROP TABLE IF EXISTS `power`;
CREATE TABLE `power` (
`power_id` int(11) NOT NULL AUTO_INCREMENT,
`power_name` varchar(25) DEFAULT NULL,
`power_index` varchar(5) DEFAULT NULL,
`power_url` varchar(25) DEFAULT NULL,
`parent_id` int(11) DEFAULT NULL,
`node_id` int(11) DEFAULT NULL,
PRIMARY KEY (`power_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
#用户角色中间表
DROP TABLE IF EXISTS `user_role_rel`;
CREATE TABLE `user_role_rel` (
`ur_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`role_id` int(11) DEFAULT NULL,
PRIMARY KEY (`ur_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
#角色权限中间表
DROP TABLE IF EXISTS `role_power_rel`;
CREATE TABLE `role_power_rel` (
`rp_id` int(11) NOT NULL AUTO_INCREMENT,
`role_id` int(11) DEFAULT NULL,
`power_id` int(11) DEFAULT NULL,
PRIMARY KEY (`rp_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
2 根据5张表,我们分析出根据用户名查询用户拥有的权限的sql语句,代码如下:
SELECT p.* from user_info u INNER JOIN user_role_rel urr
on u.user_id = urr.user_id INNER JOIN role_info r
on r.role_id = urr.role_id INNER JOIN role_power_rel rpr
on r.role_id = rpr.role_id INNER JOIN power p
on p.power_id = rpr.power_id
where u.user_name='admin'
3 根据查询语句得出的表结构,我们定义描述这个表结构的pojo类,代码如下:
@Data
public class MyNode {
private Integer powerId;
private String name;
private String icon;
private String index;
private String url;
//记录子菜单
private List<MyNode> children;
private Integer parentId;
private Integer nodeId;
}
4 定义查询sql的dao层接口
public interface MyNodeMapper {
List<MyNode> selectPower(String userName);
}
5 定义dao 层接口的sql映射文件xml,UserInfoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.hqyj.dao.UserInfoDao" >
<resultMap id="MyMap" type="com.hqyj.pojo.MyNode">
<result property="powerId" column="power_id" jdbcType="INTEGER"></result>
<result property="index" column="power_index" jdbcType="VARCHAR"></result>
<result property="name" column="power_name" jdbcType="VARCHAR"></result>
<result property="url" column="power_url" jdbcType="VARCHAR"></result>
<result property="parentId" column="parent_id" jdbcType="INTEGER"></result>
<result property="nodeId" column="node_id" jdbcType="INTEGER"></result>
</resultMap>
<select id="queryPowerByName" resultMap="MyMap" parameterType="java.lang.String">
SELECT p.* from user_info u INNER JOIN user_role_rel urr
on u.user_id = urr.user_id INNER JOIN role_info r
on r.role_id = urr.role_id INNER JOIN role_power_rel rpr
on r.role_id = rpr.role_id INNER JOIN power p
on p.power_id = rpr.power_id
where u.user_name=#{userName}
</select>
</mapper>
6 定义service接口
public interface MyNodeService {
//查询权限
HashMap<String,Object> selectPower(String userName);
}
7 定义service接口实现类,这里有一个逻辑:如何把查询的权限结果,分析出他们的父子关系,代码如下
@Override
public ResultVo queryPowerByName(String userName) {
ResultVo resultVo = new ResultVo();
List<MyNode> nodeList = userInfoDao.queryPowerByName(userName);
List<MyNode> newList = new LinkedList<>();
//构建树形结构
if (nodeList.size() > 0){
//遍历权限集合
for (MyNode myNode : nodeList){
//查找一级菜单
if (myNode.getParentId() == 0){
//创建一级菜单的子菜单集合对象
List<MyNode> childRenList = new LinkedList<>();
//查找一级菜单的子菜单
for (MyNode n : nodeList){
//看当前的菜单是不是一级菜单的子菜单
if (n.getParentId() == myNode.getNodeId()){
childRenList.add(n);
}
}
//设置子菜单到一级菜单
myNode.setChildren(childRenList);
//添加树形节点
newList.add(myNode);
}
}
resultVo.setSuccess(true);
resultVo.setData(newList);
}
return resultVo;
}
8 控制器方法
//查询权限
@GetMapping("/queryPower")
public ResultVo queryPowerByName(String userName){
return userInfoService.queryPowerByName(userName);
}
9 vue登录前端,用本地存储记录登录用户名
localStorage.setItem("userName",mythis.userInfo.name);
10 在vue系统主页面取出登录用户名,访问服务端,得到结果集赋值给绑定的权限集合node
<script>
export default {
name: "index",
data() {
return {
userName:"",//登录用户名
node:[], //树节点
}
},
methods:{
backIndex(){ //返回欢迎页面地址
this.$router.push("/welcome");
},
backLogin(){ //退出
//回到登录页面
this.$router.push("/login");
//清除登录信息
localStorage.removeItem("userName");
//刷新
this.$router.go(0);
}
},
mounted(){
//获取存在本地存储的cookie的用户名
this.userName = localStorage.getItem("userName");
//加载权限菜单
var self = this;
this.$http.get("/userInfo/queryPower",
{params:
{"userName":this.userName},
}).then(function(rs){
self.node = rs.data.data;
}).catch(function(rs){
console.log(rs);
console.log("连接服务器错误!");
})
//获取存在本地存储的sesssion的用户名
// this.userName = sessionStorage.getItem("userName");
}
}
</script>
11 这里用element-ui的权限菜单组件 显示登录用户的权限信息,代码如下
<el-menu :default-openeds="['1','2','3','4','5']" router >
<template v-for="x in node">
<el-submenu :index="x.index">
<template slot="title"><i class="el-icon-message"></i>{
{x.name}}
</template>
<template v-for="y in x.children">
<el-menu-item :index="y.url"><i class="el-icon-message"></i>{
{y.name}}</el-menu-item>
</template>
</el-submenu>
</template>
</el-menu>
12 完毕