【权限】
系统中提供了很多功能, 但是并不是所有用户都能操作这些功能。
我们需要对这些功能访问进行控制
1. 认证
系统提供的用于识别用户身份的功能, 通常登陆就是认证
(让系统知道你是谁)
2. 授权
系统授予用户可以操作某些功能的许可
(让系统知道你能做什么)
【常见的权限控制方式】
1. URL拦截权限控制
使用过滤器或者拦截器拦截客户端发送的请求,
在过滤器或者拦截器中进行权限的效验
如果效验通过, 放行。
效验不通过, 跳转到权限不足的页面。
2. 方法注解权限控制
底层基于代理技术实现
如
@HasPrivilege("staff.delete") // 执行这个方法需要delete权限
public String delete(){
// 调用service删除
}
【权限模块数据模型】
用户表(多对多)角色表(多对多)权限表
菜单表(多对多)权限表(多对多)操作表
【任务】
1. 登陆后显示对应的菜单
首先要知道菜单的样式是父子菜单
所以返回的菜单对象不能单纯的List<Menu>,而是List<MenuVo>
public class MenuVo {
private Integer menuid;
private String menuname;
private String menuurl;
private Menu pid;
//子菜单
private List<Menu> childList;
登陆成功后,根据用户id查询该用户的所有角色id(用户角色表)
在控制层的登录方法中
//权限认证,返回的是菜单信息
List<MenuVo> list = us.getMenuVo(user);
service层中的方法:
根据所有角色id查询所有权限id(角色权限表)
根据所有权限id查询所有菜单id(权限菜单表)
根据所有菜单id查询菜单信息(菜单表)
菜单信息PO -> VO(内部包含自己的List)
@Override
public List<MenuVo> getMenuVo(User user) {
System.out.println("user"+user);
// 登陆成功后,根据用户id查询该用户的所有角色id(用户角色表)
List<Integer> permissionidList = getPerListByUserid(user.getUserid());
// 根据所有权限id查询所有菜单id(权限菜单表)
PermissionMenuExample permissionMenuExample = new PermissionMenuExample();
cn.zzpigt.bean.PermissionMenuExample.Criteria permissMenuCriteria = permissionMenuExample.createCriteria();
permissMenuCriteria.andPermissionidIn(permissionidList);
List<PermissionMenu> permenuList = permissionMenuMapper.selectByExample(permissionMenuExample);
List<Integer> menuidList = new ArrayList<>();
if(permenuList == null || permenuList.size() == 0){
return null;
}
for (PermissionMenu pm : permenuList) {
menuidList.add(pm.getMenuid());
}
System.out.println("所有菜单id"+menuidList);
// 根据所有菜单id查询菜单信息(菜单表)
// 菜单信息PO -> VO(内部包含自己的List)
List<MenuVo> list = new ArrayList<>();
for (Integer menuid : menuidList) {
//根据id查到这个menu
Menu menu = menuMapper.selectByPrimaryKey(menuid);
MenuVo menuVo = new MenuVo(menu);
//vo中的pid父菜单
menuVo.setPid(menuMapper.selectByPrimaryKey(menu.getPid()));
//list中的子菜单
MenuExample menuExample = new MenuExample();
cn.zzpigt.bean.MenuExample.Criteria menuCriteria = menuExample.createCriteria();
menuCriteria.andPidEqualTo(menuid);
List<Menu> childList = menuMapper.selectByExample(menuExample);
menuVo.setChildList(childList);
list.add(menuVo);
}
for (MenuVo menuVo : list) {
System.out.println("这是menuvo测试循环: "+menuVo);
}
return list;
}
首页的树形菜单左侧菜单栏用el表达式填充
子菜单填充到上方
左侧菜单的jsp页面
<!-- 模版的特殊性,左侧菜单栏的data-id需要不同的数,否则会影响到点击选中 -->
<c:set var="listcount" value="2"></c:set>
<!-- 嵌套循环遍历,显示父菜单和子菜单信息 -->
<c:forEach items="${list}" var="menu" varStatus="i">
<c:if test="${empty (menu.pid) }">
<li class="nav-li"><a href="javascript:;" class="ue-clear"><i class="nav-ivon"></i><span class="nav-text">${menu.menuname}</span></a>
<ul class="subnav last-nav-li">
<c:forEach items="${menu.childList}" var="childMenu" varStatus="j">
<li href="${pageContext.request.contextPath}/${childMenu.menuurl}/list.action"class="subnav-li "data-id="${listcount }">
<a href="${pageContext.request.contextPath }/${childMenu.menuurl}/list.action" class="ue-clear">
<i class="subnav-icon"></i><span class="subnav-text">${childMenu.menuname }</span>
</a>
</li>
<!-- 模版的特殊性,左侧菜单栏的data-id需要不同的数,否则会影响到点击选中 -->
<c:set var="listcount" value="${listcount+1}" />
</c:forEach>
</ul>
</li>
</c:if>
</c:forEach>
2. 拦截用户不具备权限的请求
在用户登录成功后返回的用户对象,获取用户id
//去业务逻辑层判断数据是否正确 ,要获取session里面的验证码
User user = us.checkUserAndCode(vo, session);
//授权,返回List<String>
List<String> perActionList = us.getPermissionOp(user);
//放入session中给拦截器用
session.setAttribute("perActionList", perActionList);
根据用户id查询该用户的所有角色id(用户角色表)
根据角色id查询所有权限id(角色权限表)
根据所有权限id查询所有操作id(权限操作表)
根据所有操作id查询操作信息(操作表)
@Override
public List<String> getPermissionOp(User user) {
// 从session取出用户id,用户id查询该用户的所有角色id(用户角色表)
// 根据所有角色id查询所有权限id(角色权限表)
List<Integer> permissionidList = getPerListByUserid(user.getUserid());
// 根据所有权限id查询所有操作id(权限操作表)
PermissionOperateExample permissionOperateExample = new PermissionOperateExample();
cn.zzpigt.bean.PermissionOperateExample.Criteria perOperateCriteria = permissionOperateExample.createCriteria();
perOperateCriteria.andPermissionidIn(permissionidList);
List<PermissionOperate> perOperateList = perOperateMapper.selectByExample(permissionOperateExample);
List<Integer> operateidList = new ArrayList<>();
if(perOperateList == null || perOperateList.size() == 0){
return null;
}
for (PermissionOperate permissionOperate : perOperateList) {
operateidList.add(permissionOperate.getOperateid());
}
// 根据所有操作id查询操作信息(操作表)
OperateExample operateExample = new OperateExample();
cn.zzpigt.bean.OperateExample.Criteria operaterCriteria = operateExample.createCriteria();
operaterCriteria.andOperateidIn(operateidList);
List<Operate> operateList = operateMapper.selectByExample(operateExample);
List<String> operateActionList = new ArrayList<>();
for (Operate operate : operateList) {
operateActionList.add(operate.getOperateaction());
}
System.out.println("operateActionList"+operateActionList);
return operateActionList;
}
放到session中
用户发出请求时, 由权限拦截器拦截
(可设置在登陆拦截器之后)
springmvc配置文件中添加拦截器
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<!-- 授权拦截器 -->
<bean class="cn.zzpigt.interceptor.PermissionInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
从session操作信息
遍历操作信息(或使用contains),判断用户是否有权限进行本次访问。
这个拦截器还是要再做一次登陆拦截器的逻辑,因为是全局的拦截器,所以用户登录或者获取验证码的时候也要走这个拦截器,蛋疼.
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception {
User user = (User) request.getSession().getAttribute("user");
//权限拦截
List<String> operate = (List<String>) request.getSession().getAttribute("perActionList");
if(operate != null && operate.size() > 0){
//遍历用户权限列表,和看看是否包含请求的url
for (String op : operate) {
if(request.getRequestURI().contains(op) || request.getRequestURI().contains("depttable")|| request.getRequestURI().contains("Attend")|| request.getRequestURI().contains("User")){
System.out.println("没被拦截的,通过:" + request.getRequestURI());
return true;
}
}
}
//登录或者获取验证码的情况放行
else if(user != null || request.getRequestURI().contains("login") || request.getRequestURI().contains("checkCode")){
return true;
}
System.out.println("被拦截的:" + request.getRequestURI());
//被拦截就重定向到首页
response.sendRedirect(request.getContextPath() + "/main.jsp");
return false;
}
[SQL测试]
登陆成功后,根据用户id查询该用户的所有角色id(用户角色表)
21
SELECT roleid FROM user_role WHERE userid = 21;
27
根据所有角色id查询所有权限id(角色权限表)
SELECT permissionid FROM role_permission WHERE roleid IN (27);
2
3
4
5
13
14
15
16
18
根据所有权限id查询所有菜单id(权限菜单表)
SELECT menuid FROM permission_menu WHERE permissionid IN (2,3,4,5,13,14,15,16,18);
2
3
4
5
13
14
15
16
18
根据所有菜单id查询菜单信息(菜单表)
SELECT * FROM menu WHERE menuid IN (2,3,4,5,13,14,15,16,18);