zoukankan      html  css  js  c++  java
  • Apache Shiro(六)-基于URL配置权限

    数据库

    先准备数据库啦。

     1 DROP DATABASE IF EXISTS shiro;
     2 CREATE DATABASE shiro DEFAULT CHARACTER SET utf8;
     3 USE shiro;
     4     
     5 drop table if exists user;
     6 drop table if exists role;
     7 drop table if exists permission;
     8 drop table if exists user_role;
     9 drop table if exists role_permission;
    10     
    11 create table user (
    12   id bigint auto_increment,
    13   name varchar(100),
    14   password varchar(100),
    15   salt varchar(100),
    16   constraint pk_users primary key(id)
    17 ) charset=utf8 ENGINE=InnoDB;
    18     
    19 create table role (
    20   id bigint auto_increment,
    21   name varchar(100),
    22   desc_ varchar(100),
    23   constraint pk_roles primary key(id)
    24 ) charset=utf8 ENGINE=InnoDB;
    25     
    26 create table permission (
    27   id bigint auto_increment,
    28   name varchar(100),
    29   desc_ varchar(100),
    30   url varchar(100),
    31   constraint pk_permissions primary key(id)
    32 ) charset=utf8 ENGINE=InnoDB;
    33     
    34 create table user_role (
    35   id bigint auto_increment,
    36   uid bigint,
    37   rid bigint,
    38   constraint pk_users_roles primary key(id)
    39 ) charset=utf8 ENGINE=InnoDB;
    40     
    41 create table role_permission (
    42   id bigint auto_increment,
    43   rid bigint,
    44   pid bigint,
    45   constraint pk_roles_permissions primary key(id)
    46 ) charset=utf8 ENGINE=InnoDB;
    47  
    48 INSERT INTO `permission` VALUES (1,'addProduct','增加产品','/addProduct');
    49 INSERT INTO `permission` VALUES (2,'deleteProduct','删除产品','/deleteProduct');
    50 INSERT INTO `permission` VALUES (3,'editeProduct','编辑产品','/editeProduct');
    51 INSERT INTO `permission` VALUES (4,'updateProduct','修改产品','/updateProduct');
    52 INSERT INTO `permission` VALUES (5,'listProduct','查看产品','/listProduct');
    53 INSERT INTO `permission` VALUES (6,'addOrder','增加订单','/addOrder');
    54 INSERT INTO `permission` VALUES (7,'deleteOrder','删除订单','/deleteOrder');
    55 INSERT INTO `permission` VALUES (8,'editeOrder','编辑订单','/editeOrder');
    56 INSERT INTO `permission` VALUES (9,'updateOrder','修改订单','/updateOrder');
    57 INSERT INTO `permission` VALUES (10,'listOrder','查看订单','/listOrder');
    58 INSERT INTO `role` VALUES (1,'admin','超级管理员');
    59 INSERT INTO `role` VALUES (2,'productManager','产品管理员');
    60 INSERT INTO `role` VALUES (3,'orderManager','订单管理员');
    61 INSERT INTO `role_permission` VALUES (1,1,1);
    62 INSERT INTO `role_permission` VALUES (2,1,2);
    63 INSERT INTO `role_permission` VALUES (3,1,3);
    64 INSERT INTO `role_permission` VALUES (4,1,4);
    65 INSERT INTO `role_permission` VALUES (5,1,5);
    66 INSERT INTO `role_permission` VALUES (6,1,6);
    67 INSERT INTO `role_permission` VALUES (7,1,7);
    68 INSERT INTO `role_permission` VALUES (8,1,8);
    69 INSERT INTO `role_permission` VALUES (9,1,9);
    70 INSERT INTO `role_permission` VALUES (10,1,10);
    71 INSERT INTO `role_permission` VALUES (11,2,1);
    72 INSERT INTO `role_permission` VALUES (12,2,2);
    73 INSERT INTO `role_permission` VALUES (13,2,3);
    74 INSERT INTO `role_permission` VALUES (14,2,4);
    75 INSERT INTO `role_permission` VALUES (15,2,5);
    76 INSERT INTO `role_permission` VALUES (50,3,10);
    77 INSERT INTO `role_permission` VALUES (51,3,9);
    78 INSERT INTO `role_permission` VALUES (52,3,8);
    79 INSERT INTO `role_permission` VALUES (53,3,7);
    80 INSERT INTO `role_permission` VALUES (54,3,6);
    81 INSERT INTO `role_permission` VALUES (55,3,1);
    82 INSERT INTO `role_permission` VALUES (56,5,11);
    83 INSERT INTO `user` VALUES (1,'zhang3','a7d59dfc5332749cb801f86a24f5f590','e5ykFiNwShfCXvBRPr3wXg==');
    84 INSERT INTO `user` VALUES (2,'li4','43e28304197b9216e45ab1ce8dac831b','jPz19y7arvYIGhuUjsb6sQ==');
    85 INSERT INTO `user_role` VALUES (43,2,2);
    86 INSERT INTO `user_role` VALUES (45,1,1);
    点击展开

    基于前面的知识点继续进行

    下面只展示基于前面的代码做修改

    PageController.java

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

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

    PermissionService.java

    增加了两个方法 needInterceptor,listPermissionURLs

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

    PermissionServiceImpl.java

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

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

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

    URLPathMatchingFilter.java

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

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

    applicationContext-shiro.xml

    首先声明URLPathMatchingFilter 过滤器

    <bean id="urlPathMatchingFilter" class="com.how2java.filter.URLPathMatchingFilter"/>

    在shiro中使用这个过滤器

    <entry key="url" value-ref="urlPathMatchingFilter" />

    过滤规则是所有访问

    /** = url
      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      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     <!-- url过滤器 -->        
     16     <bean id="urlPathMatchingFilter" class="com.how2java.filter.URLPathMatchingFilter"/>
     17           
     18     <!-- 配置shiro的过滤器工厂类,id- shiroFilter要和我们在web.xml中配置的过滤器一致 -->
     19     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
     20         <!-- 调用我们配置的权限管理器 -->
     21         <property name="securityManager" ref="securityManager" />
     22         <!-- 配置我们的登录请求地址 -->
     23         <property name="loginUrl" value="/login" />
     24         <!-- 如果您请求的资源不再您的权限范围,则跳转到/403请求地址 -->
     25         <property name="unauthorizedUrl" value="/unauthorized" />
     26         <!-- 退出 -->
     27         <property name="filters">
     28             <util:map>
     29                 <entry key="logout" value-ref="logoutFilter" />
     30                 <entry key="url" value-ref="urlPathMatchingFilter" />
     31             </util:map>
     32         </property>
     33         <!-- 权限配置 -->
     34         <property name="filterChainDefinitions">
     35             <value>
     36                 <!-- anon表示此地址不需要任何权限即可访问 -->
     37                 /login=anon
     38                 /index=anon
     39                 /static/**=anon
     40                 <!-- 只对业务功能进行权限管理,权限配置本身不需要没有做权限要求,这样做是为了不让初学者混淆 -->
     41                 /config/**=anon
     42                 /doLogout=logout
     43                 <!--所有的请求(除去配置的静态资源请求或请求地址为anon的请求)都要通过过滤器url -->
     44                 /** = url
     45             </value>
     46         </property>
     47     </bean>
     48     <!-- 退出过滤器 -->
     49     <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
     50         <property name="redirectUrl" value="/index" />
     51     </bean>
     52   
     53     <!-- 会话ID生成器 -->
     54     <bean id="sessionIdGenerator"
     55         class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" />
     56     <!-- 会话Cookie模板 关闭浏览器立即失效 -->
     57     <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
     58         <constructor-arg value="sid" />
     59         <property name="httpOnly" value="true" />
     60         <property name="maxAge" value="-1" />
     61     </bean>
     62     <!-- 会话DAO -->
     63     <bean id="sessionDAO"
     64         class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
     65         <property name="sessionIdGenerator" ref="sessionIdGenerator" />
     66     </bean>
     67     <!-- 会话验证调度器,每30分钟执行一次验证 ,设定会话超时及保存 -->
     68     <bean name="sessionValidationScheduler"
     69         class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler">
     70         <property name="interval" value="1800000" />
     71         <property name="sessionManager" ref="sessionManager" />
     72     </bean>
     73     <!-- 会话管理器 -->
     74     <bean id="sessionManager"
     75         class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
     76         <!-- 全局会话超时时间(单位毫秒),默认30分钟 -->
     77         <property name="globalSessionTimeout" value="1800000" />
     78         <property name="deleteInvalidSessions" value="true" />
     79         <property name="sessionValidationSchedulerEnabled" value="true" />
     80         <property name="sessionValidationScheduler" ref="sessionValidationScheduler" />
     81         <property name="sessionDAO" ref="sessionDAO" />
     82         <property name="sessionIdCookieEnabled" value="true" />
     83         <property name="sessionIdCookie" ref="sessionIdCookie" />
     84     </bean>
     85   
     86     <!-- 安全管理器 -->
     87     <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
     88         <property name="realm" ref="databaseRealm" />
     89         <property name="sessionManager" ref="sessionManager" />
     90     </bean>
     91     <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
     92     <bean
     93         class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
     94         <property name="staticMethod"
     95             value="org.apache.shiro.SecurityUtils.setSecurityManager" />
     96         <property name="arguments" ref="securityManager" />
     97     </bean>
     98   
     99     <!-- 密码匹配器 -->
    100     <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
    101         <property name="hashAlgorithmName" value="md5"/>
    102         <property name="hashIterations" value="2"/>
    103         <property name="storedCredentialsHexEncoded" value="true"/>
    104     </bean>
    105   
    106     <bean id="databaseRealm" class="com.how2java.realm.DatabaseRealm">
    107         <property name="credentialsMatcher" ref="credentialsMatcher"/>
    108     </bean>
    109       
    110     <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
    111     <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
    112 </beans>
    点击展开

    jsp 们

    jsp前端页面这里就不贴了。先要的到下面下载。

    关于角色

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

    结束

    大家可以跑起来试一下。

    代码下载地址:https://gitee.com/fengyuduke/my_open_resources/blob/master/shiro-url.zip

    另外:项目所需jar包下载地址 https://gitee.com/fengyuduke/my_open_resources/tree/jarPackage/

  • 相关阅读:
    销售人员个人提升经典书籍推荐
    销售必看的书籍推荐
    我在公司敲代码,你却在家和老王………————程序员的那些梗
    某程序员动了公司的祖传代码"屎山",半年后怒交辞职报告!
    为什么说程序员的前三年不要太看重工资水平?
    好的员工关系应该是怎样的?
    粒子群优化算法(PSO)python 3实现
    Python基础篇-安装python
    Python设置matplotlib.plot的坐标轴刻度间隔以及刻度范围
    空TreeList添加节点不显示
  • 原文地址:https://www.cnblogs.com/fengyuduke/p/10496019.html
Copyright © 2011-2022 走看看