• Shiro第五篇【授权过滤、注解、JSP标签方式、与ehcache整合】


    授权过滤器测试

    我们的授权过滤器使用的是permissionsAuthorizationFilter来进行拦截。我们可以在application-shiro中配置filter规则

    
            <!--商品查询需要商品查询权限 -->
            /items/queryItems.action = perms[item:query]
            /items/editItems.action = perms[item:edit] 

    测试流程:
    1、在applicationContext-shiro.xml中配置filter规则

    • <!--商品查询需要商品查询权限 -->
    • /items/queryItems.action = perms[item:query]

    2、用户在认证通过后,请求/items/queryItems.action
    3、被PermissionsAuthorizationFilter拦截,发现需要“item:query”权限
    4、PermissionsAuthorizationFilter**调用realm中的doGetAuthorizationInfo获取数据库中正确的权限**
    5、PermissionsAuthorizationFilter对item:query 和从realm中获取权限进行对比,如果“item:query”在realm返回的权限列表中,授权通过。

    realm中获取认证的信息,查询出该用户对应的权限,封装到simpleAuthorizationInfo中,PermissionsAuthorizationFilter会根据对应的权限来比对。

    
    @Override
        protected AuthorizationInfo doGetAuthorizationInfo(
                PrincipalCollection principals) {
    
            //从 principals获取主身份信息
            //将getPrimaryPrincipal方法返回值转为真实身份类型(在上边的doGetAuthenticationInfo认证通过填充到SimpleAuthenticationInfo中身份类型),
            ActiveUser activeUser =  (ActiveUser) principals.getPrimaryPrincipal();
    
            //根据身份信息获取权限信息
            //从数据库获取到权限数据
            List<SysPermission> permissionList = null;
            try {
                permissionList = sysService.findPermissionListByUserId(activeUser.getUserid());
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            //单独定一个集合对象 
            List<String> permissions = new ArrayList<String>();
            if(permissionList!=null){
                for(SysPermission sysPermission:permissionList){
                    //将数据库中的权限标签 符放入集合
                    permissions.add(sysPermission.getPercode());
                }
            }
    
    
        /*  List<String> permissions = new ArrayList<String>();
            permissions.add("user:create");//用户的创建
            permissions.add("item:query");//商品查询权限
            permissions.add("item:add");//商品添加权限
            permissions.add("item:edit");//商品修改权限
    */      //....
    
            //查到权限数据,返回授权信息(要包括 上边的permissions)
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            //将上边查询到授权信息填充到simpleAuthorizationInfo对象中
            simpleAuthorizationInfo.addStringPermissions(permissions);
    
            return simpleAuthorizationInfo;
        }

    在bean中我们已经配置了:如果没有权限,那么跳转到哪个JSP页面了

    
            <!-- 通过unauthorizedUrl指定没有权限操作时跳转页面-->
            <property name="unauthorizedUrl" value="/refuse.jsp" />

    到目前为止,现在问题又来了:

    1、在applicationContext-shiro.xml中配置过虑器链接,需要将全部的url和权限对应起来进行配置,比较发麻不方便使用。

    2、每次授权都需要调用realm查询数据库,对于系统性能有很大影响,可以通过shiro缓存来解决。


    使用注解式和标签式配置授权

    上面的那种方法,还是需要我们将全部的url和权限对应起来进行配置,是比较不方便的。我们可以使用授权的另外两种方式

    • 注解式
    • 标签式

    注解式

    如果要使用注解式,那么就必须在Spring中开启controller类aop支持

    
        <!-- 开启aop,对类代理 -->
        <aop:config proxy-target-class="true"></aop:config>
        <!-- 开启shiro注解支持 -->
        <bean
            class="
    org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
            <property name="securityManager" ref="securityManager" />
        </bean>

    在Controller中使用注解来进行配置就行了,就不用在我们的application-shiro中全部集中配置了

    
        //商品信息方法
        @RequestMapping("/queryItems")
        @RequiresPermissions("item:query")//执行queryItems需要"item:query"权限
        public ModelAndView queryItems(HttpServletRequest request) throws Exception {
    
            System.out.println(request.getParameter("id"));
    
            //调用service查询商品列表
            List<ItemsCustom> itemsList = itemsService.findItemsList(null);
    
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("itemsList", itemsList);
            // 指定逻辑视图名
            modelAndView.setViewName("itemsList");
    
            return modelAndView;
        }

    jsp标签 授权

    这里写图片描述

    这里写图片描述

    当调用controller的一个方法,由于该 方法加了@RequiresPermissions(“item:query”) ,shiro调用realm获取数据库中的权限信息,看”item:query”是否在权限数据中存在,如果不存在就拒绝访问,如果存在就授权通过。

    当展示一个jsp页面时,页面中如果遇到,shiro调用realm获取数据库中的权限信息,看item:update是否在权限数据中存在,如果不存在就拒绝访问,如果存在就授权通过。


    Shiro缓存

    针对上边授权频繁查询数据库,需要使用shiro缓存

    缓存流程

    shiro中提供了对认证信息和授权信息的缓存。shiro默认是关闭认证信息缓存的,对于授权信息的缓存shiro默认开启的。主要研究授权信息缓存,因为授权的数据量大。

    用户认证通过。

    该用户第一次授权:调用realm查询数据库
    该用户第二次授权:不调用realm查询数据库,直接从缓存中取出授权信息(权限标识符)。

    使用ehcache和Shiro整合

    导入jar包

    这里写图片描述

    配置缓存管理器,注入到安全管理器中

    
    <!-- 缓存管理器 -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
            <property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
        </bean>
    
    
        <!-- securityManager安全管理器 -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="customRealm" />
            <!-- 注入缓存管理器 -->
            <property name="cacheManager" ref="cacheManager"/>
        </bean>

    ehcache的配置文件shiro-ehcache.xml

    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
        <!--diskStore:缓存数据持久化的目录 地址  -->
        <diskStore path="F:developehcache" />
        <defaultCache 
            maxElementsInMemory="1000" 
            maxElementsOnDisk="10000000"
            eternal="false" 
            overflowToDisk="false" 
            diskPersistent="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120" 
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        </defaultCache>
    </ehcache>
    

    缓存清空

    如果用户正常退出,缓存自动清空。
    如果用户非正常退出,缓存自动清空。

    还有一种情况:

    • 当管理员修改了用户的权限,但是该用户还没有退出,在默认情况下,修改的权限无法立即生效。需要手动进行编程实现:在权限修改后调用realm的clearCache方法清除缓存。

    清除缓存:

    
        //清除缓存
        public void clearCached() {
            PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
            super.clearCache(principals);
        }

    sessionManager

    和shiro整合后,使用shiro的session管理,shiro提供sessionDao操作 会话数据。

    配置sessionManager

    
    <!-- 会话管理器 -->
        <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
            <!-- session的失效时长,单位毫秒 -->
            <property name="globalSessionTimeout" value="600000"/>
            <!-- 删除失效的session -->
            <property name="deleteInvalidSessions" value="true"/>
        </bean>

    注入到安全管理器中

    
    <!-- securityManager安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="customRealm" />
            <!-- 注入缓存管理器 -->
            <property name="cacheManager" ref="cacheManager"/>
            <!-- 注入session管理器 -->
            <property name="sessionManager" ref="sessionManager" />
    
    </bean>

  • 相关阅读:
    我的第一个python web开发框架(4)——数据库结构设计与创建
    我的第一个python web开发框架(3)——怎么开始?
    我的第一个python web开发框架(2)——一个简单的小外包
    我的第一个python web开发框架(1)——前言
    让python bottle框架支持jquery ajax的RESTful风格的PUT和DELETE等请求(新方法)
    让python bottle框架支持jquery ajax的RESTful风格的PUT和DELETE等请求
    python服务器环境搭建(3)——参数配置
    python服务器环境搭建(2)——安装相关软件
    python服务器环境搭建(1)——本地服务器准备
    一个按成绩排序SQL的写法问题
  • 原文地址:https://www.cnblogs.com/zhong-fucheng/p/7554343.html
Copyright © 2020-2023  润新知