Shiro集成SSM基于动态URL权限管理(二)

这个案例基于上一个demo扩展而来。所以数据库表,在Shiro集成SSM基于URL权限管理(一)开篇的一致。如果上个demo操作的建议重新导入一次,避免出现问题。

而这次不是通过固定写在方法上的注解实现的,而是通过权限灵活配置实现的

PageController.java

首先是PageController.java 里原本通过注解方式的@RequiresPermissions和@RequiresRoles 注释掉了

Shiro集成SSM基于动态URL权限管理(二)_第1张图片

 1 import org.springframework.stereotype.Controller;
 2 import org.springframework.web.bind.annotation.RequestMapping;
 3 import org.springframework.web.bind.annotation.RequestMethod;
 4  
 5 //专门用于显示页面的控制器
 6 @Controller
 7 @RequestMapping("")
 8 public class PageController {
 9      
10     @RequestMapping("index")
11     public String index(){
12         return "index";
13     }
14      
15 //  @RequiresPermissions("deleteOrder")
16     @RequestMapping("deleteOrder")
17     public String deleteOrder(){
18         return "deleteOrder";
19     }
20 //  @RequiresRoles("productManager")
21     @RequestMapping("deleteProduct")
22     public String deleteProduct(){
23         return "deleteProduct";
24     }
25     @RequestMapping("listProduct")
26     public String listProduct(){
27         return "listProduct";
28     }
29      
30     @RequestMapping(value="/login",method=RequestMethod.GET) 
31     public String login(){
32         return "login";
33     }
34     @RequestMapping("unauthorized")
35     public String noPerms(){
36         return "unauthorized";
37     }
38  
39 }
View Code

PermissionService.java

增加了两个方法 needInterceptor,listPermissionURLs

代码如下:

 1 import java.util.List;
 2 import java.util.Set;
 3  
 4 import com.how2java.pojo.Permission;
 5 import com.how2java.pojo.Role;
 6  
 7 public interface PermissionService {
 8     public Set listPermissions(String userName);
 9  
10     public List list();
11  
12     public void add(Permission permission);
13  
14     public void delete(Long id);
15  
16     public Permission get(Long id);
17  
18     public void update(Permission permission);
19  
20     public List list(Role role);
21  
22     public boolean needInterceptor(String requestURI);
23  
24     public Set listPermissionURLs(String userName);
25  
26 }
View Code

PermissionServiceImpl.java

为两个方法 needInterceptor,listPermissionURLs 增加了实现
needInterceptor 表示是否要进行拦截,判断依据是如果访问的某个url,在权限系统里存在,就要进行拦截。 如果不存在,就放行了。
这一种策略,也可以切换成另一个,即,访问的地址如果不存在于权限系统中,就提示没有拦截。 这两种做法没有对错之分,取决于业务上希望如何制定权限策略。

listPermissionURLs(User user) 用来获取某个用户所拥有的权限地址集合

  1 import java.util.ArrayList;
  2 import java.util.HashSet;
  3 import java.util.List;
  4 import java.util.Set;
  5  
  6 import org.springframework.beans.factory.annotation.Autowired;
  7 import org.springframework.stereotype.Service;
  8  
  9 import com.how2java.mapper.PermissionMapper;
 10 import com.how2java.mapper.RolePermissionMapper;
 11 import com.how2java.pojo.Permission;
 12 import com.how2java.pojo.PermissionExample;
 13 import com.how2java.pojo.Role;
 14 import com.how2java.pojo.RolePermission;
 15 import com.how2java.pojo.RolePermissionExample;
 16 import com.how2java.service.PermissionService;
 17 import com.how2java.service.RoleService;
 18 import com.how2java.service.UserService;
 19  
 20 @Service
 21 public class PermissionServiceImpl implements PermissionService {
 22  
 23     @Autowired
 24     PermissionMapper permissionMapper;
 25     @Autowired
 26     UserService userService;
 27     @Autowired
 28     RoleService roleService;
 29     @Autowired
 30     RolePermissionMapper rolePermissionMapper;
 31  
 32     @Override
 33     public Set listPermissions(String userName) {
 34         Set result = new HashSet<>();
 35         List roles = roleService.listRoles(userName);
 36  
 37         List rolePermissions = new ArrayList<>();
 38  
 39         for (Role role : roles) {
 40             RolePermissionExample example = new RolePermissionExample();
 41             example.createCriteria().andRidEqualTo(role.getId());
 42             List rps = rolePermissionMapper.selectByExample(example);
 43             rolePermissions.addAll(rps);
 44         }
 45  
 46         for (RolePermission rolePermission : rolePermissions) {
 47             Permission p = permissionMapper.selectByPrimaryKey(rolePermission.getPid());
 48             result.add(p.getName());
 49         }
 50  
 51         return result;
 52     }
 53  
 54     @Override
 55     public void add(Permission u) {
 56         permissionMapper.insert(u);
 57     }
 58  
 59     @Override
 60     public void delete(Long id) {
 61         permissionMapper.deleteByPrimaryKey(id);
 62     }
 63  
 64     @Override
 65     public void update(Permission u) {
 66         permissionMapper.updateByPrimaryKeySelective(u);
 67     }
 68  
 69     @Override
 70     public Permission get(Long id) {
 71         return permissionMapper.selectByPrimaryKey(id);
 72     }
 73  
 74     @Override
 75     public List list() {
 76         PermissionExample example = new PermissionExample();
 77         example.setOrderByClause("id desc");
 78         return permissionMapper.selectByExample(example);
 79  
 80     }
 81  
 82     @Override
 83     public List list(Role role) {
 84         List result = new ArrayList<>();
 85         RolePermissionExample example = new RolePermissionExample();
 86         example.createCriteria().andRidEqualTo(role.getId());
 87         List rps = rolePermissionMapper.selectByExample(example);
 88         for (RolePermission rolePermission : rps) {
 89             result.add(permissionMapper.selectByPrimaryKey(rolePermission.getPid()));
 90         }
 91  
 92         return result;
 93     }
 94  
 95     @Override
 96     public boolean needInterceptor(String requestURI) {
 97         List ps = list();
 98         for (Permission p : ps) {
 99             if (p.getUrl().equals(requestURI))
100                 return true;
101         }
102         return false;
103     }
104  
105     @Override
106     public Set listPermissionURLs(String userName) {
107         Set result = new HashSet<>();
108         List roles = roleService.listRoles(userName);
109  
110         List rolePermissions = new ArrayList<>();
111  
112         for (Role role : roles) {
113             RolePermissionExample example = new RolePermissionExample();
114             example.createCriteria().andRidEqualTo(role.getId());
115             List rps = rolePermissionMapper.selectByExample(example);
116             rolePermissions.addAll(rps);
117         }
118  
119         for (RolePermission rolePermission : rolePermissions) {
120             Permission p = permissionMapper.selectByPrimaryKey(rolePermission.getPid());
121             result.add(p.getUrl());
122         }
123  
124         return result;
125     }
126  
127 }
View Code

URLPathMatchingFilter.java

PathMatchingFilter 是shiro 内置过滤器 PathMatchingFilter 继承了这个它。
基本思路如下:
1. 如果没登录就跳转到登录
2. 如果当前访问路径没有在权限系统里维护,则允许访问
3. 当前用户所拥有的权限如果不包含当前的访问地址,则跳转到/unauthorized,否则就允许访问

代码如下:

 1 import java.util.Set;
 2  
 3 import javax.servlet.ServletRequest;
 4 import javax.servlet.ServletResponse;
 5  
 6 import org.apache.shiro.SecurityUtils;
 7 import org.apache.shiro.authz.UnauthorizedException;
 8 import org.apache.shiro.subject.Subject;
 9 import org.apache.shiro.web.filter.PathMatchingFilter;
10 import org.apache.shiro.web.util.WebUtils;
11 import org.springframework.beans.factory.annotation.Autowired;
12  
13 import com.how2java.service.PermissionService;
14  
15 public class URLPathMatchingFilter extends PathMatchingFilter {
16     @Autowired
17     PermissionService permissionService;
18  
19     @Override
20     protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue)
21             throws Exception {
22         String requestURI = getPathWithinApplication(request);
23  
24         System.out.println("requestURI:" + requestURI);
25  
26         Subject subject = SecurityUtils.getSubject();
27         // 如果没有登录,就跳转到登录页面
28         if (!subject.isAuthenticated()) {
29             WebUtils.issueRedirect(request, response, "/login");
30             return false;
31         }
32  
33         // 看看这个路径权限里有没有维护,如果没有维护,一律放行(也可以改为一律不放行)
34         boolean needInterceptor = permissionService.needInterceptor(requestURI);
35         if (!needInterceptor) {
36             return true;
37         } else {
38             boolean hasPermission = false;
39             String userName = subject.getPrincipal().toString();
40             Set permissionUrls = permissionService.listPermissionURLs(userName);
41             for (String url : permissionUrls) {
42                 // 这就表示当前用户有这个权限
43                 if (url.equals(requestURI)) {
44                     hasPermission = true;
45                     break;
46                 }
47             }
48  
49             if (hasPermission)
50                 return true;
51             else {
52                 UnauthorizedException ex = new UnauthorizedException("当前用户没有访问路径 " + requestURI + " 的权限");
53  
54                 subject.getSession().setAttribute("ex", ex);
55  
56                 WebUtils.issueRedirect(request, response, "/unauthorized");
57                 return false;
58             }
59  
60         }
61  
62     }
63 }
View Code

applicationContext-shiro.xml

首先声明URLPathMatchingFilter 过滤器


shiro中使用这个过滤器

过滤规则是所有访问

/** = url

代码如下:

  1 
  2   3     xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util"
  4     xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
  5     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
  6     xmlns:aop="http://www.springframework.org/schema/aop"
  7     xsi:schemaLocation="http://www.springframework.org/schema/beans
  8     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/tx
  9     http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context
 10     http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc
 11     http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop
 12     http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/util
 13     http://www.springframework.org/schema/util/spring-util.xsd">
 14       
 15             
 16     class="com.how2java.filter.URLPathMatchingFilter"/>
 17           
 18     
 19     class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
 20         
 21         
 22         
 23         
 24         
 25         
 26         
 27         
 28             
 29                 
 30                 
 31             
 32         
 33         
 34         
 35             
 36                 
 37                 /login=anon
 38                 /index=anon
 39                 /static/**=anon
 40                 
 41                 /config/**=anon
 42                 /doLogout=logout
 43                 
 44                 /** = url
 45             
 46         
 47     
 48     
 49     
 50         
 51     
 52   
 53     
 54      55         class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" />
 56     
 57     
 58         
 59         
 60         
 61     
 62     
 63      64         class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
 65         
 66     
 67     
 68      69         class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler">
 70         
 71         
 72     
 73     
 74      75         class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
 76         
 77         
 78         
 79         
 80         
 81         
 82         
 83         
 84     
 85   
 86     
 87     
 88         
 89         
 90     
 91     
 92      93         class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
 94          95             value="org.apache.shiro.SecurityUtils.setSecurityManager" />
 96         
 97     
 98   
 99     
100     
101         
102         
103         
104     
105   
106     
107         
108     
109       
110     
111     
112 
View Code

jsp做了些文字上的改动

index.jsp

 1 <%@ page language="java" contentType="text/html; charset=UTF-8"
 2     pageEncoding="UTF-8"%>
 3 
 4 
 5 
 6  
 7 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
 8  
 9 
10  
11 
12 
13  
14 
class="workingroom"> 15
class="loginDiv"> 16 17 if test="${empty subject.principal}"> 18 登录
19
if> 20 if test="${!empty subject.principal}"> 21 class="desc">你好,${subject.principal}, 22 退出
23
if> 24 25 查看产品class="desc">(要有查看产品权限, zhang3有,li4 有)
26 删除产品class="desc">(要有删除产品权限, zhang3有,li4 有)
27 删除订单class="desc">(要有删除订单权限, zhang3有,li4没有)
28
29 30 31
View Code

deleteOrder.jsp

 1 <%@ page language="java" contentType="text/html; charset=UTF-8"
 2     pageEncoding="UTF-8" import="java.util.*"%>
 3   
 4 
 5   
 6 
 7 
 8  
 9 
class="workingroom"> 10 11 deleteOrder.jsp,能进来
就表示拥有 deleteOrder 权限 12
13 返回 14
View Code

deleteProduct.jsp

 1 <%@ page language="java" contentType="text/html; charset=UTF-8"
 2     pageEncoding="UTF-8" import="java.util.*"%>
 3   
 4 
 5   
 6 
 7 
 8  
 9 
class="workingroom"> 10 11 deleteProduct.jsp,能进来
就表示拥有 deleteProduct 权限 12
13 返回 14
View Code

listProduct.jsp

 1 <%@ page language="java" contentType="text/html; charset=UTF-8"
 2     pageEncoding="UTF-8" import="java.util.*"%>
 3   
 4 
 5   
 6 
 7 
 8  
 9 
class="workingroom"> 10 11 listProduct.jsp,能进来
就表示拥有 listProduct 权限 12
13 返回 14
View Code

打开浏览器测试,finish

重启Tomcat测试,业务测试地址:

http://127.0.0.1:8080/shirossm_dynamicURL/index

权限配置测试地址: 

http://127.0.0.1:8080/shirossm_dynamicURL/config/listUser

为什么角色不对应URL

权限通过url进行灵活配置了。 但是角色还没有和url对应起来。 为什么不把角色也对应起来呢?
从代码开发的角度讲是可以做的,无非就是在 role表上增加一个url 字段。 但是从权限管理本身的角度看,当一个url 既对应权限表的数据,又对应角色表的数据,反而容易产生混淆。
反倒是现在这种,url地址,仅仅和权限表关联起来,在逻辑上明晰简单,也更容易维护。 所以就放弃了角色表也进行url维护的做法了。

 最后,同样地,需要demo的留言私发!!!

你可能感兴趣的