• 简单的spring+shiro权限控制


    1.配置ehcache.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache updateCheck="false" dynamicConfig="false">
        <diskStore path="java.io.tmpdir"/>
        
       <cache name="authorizationCache"
               maxEntriesLocalHeap="2000"
               eternal="false"
               timeToIdleSeconds="1800"
               timeToLiveSeconds="1800"
               overflowToDisk="false"
               statistics="true">
        </cache>
    
        <cache name="authenticationCache"
               maxEntriesLocalHeap="2000"
               eternal="false"
               timeToIdleSeconds="1800"
               timeToLiveSeconds="1800"
               overflowToDisk="false"
               statistics="true">
        </cache>
        
        <cache name="activeSessionCache"
               maxEntriesLocalHeap="2000"
               eternal="false"
               timeToIdleSeconds="1800"
               timeToLiveSeconds="1800"
               overflowToDisk="false"
               statistics="true">
        </cache>
        
        <!-- 缓存半小时 -->
        <cache name="halfHour" 
            maxElementsInMemory="10000"
            maxElementsOnDisk="100000" 
            eternal="false" 
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800" 
            overflowToDisk="false" 
            diskPersistent="false" />
            
        <!-- 缓存一小时 -->
        <cache name="hour" 
            maxElementsInMemory="10000"
            maxElementsOnDisk="100000" 
            eternal="false" 
            timeToIdleSeconds="3600"
            timeToLiveSeconds="3600" 
            overflowToDisk="false" 
            diskPersistent="false" />
        
        <!-- 缓存一天 -->
        <cache name="oneDay" 
            maxElementsInMemory="10000"
            maxElementsOnDisk="100000" 
            eternal="false" 
            timeToIdleSeconds="86400"
            timeToLiveSeconds="86400" 
            overflowToDisk="false" 
            diskPersistent="false" />
        
        <!--
            name:缓存名称。
            maxElementsInMemory:缓存最大个数。
            eternal:对象是否永久有效,一但设置了,timeout将不起作用。
            timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
            timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
            overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
            diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
            maxElementsOnDisk:硬盘最大缓存个数。
            diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
            diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。   
            memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
            clearOnFlush:内存数量最大时是否清除。
        -->
        <defaultCache name="defaultCache"
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            maxElementsOnDisk="100000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"/>
            
    </ehcache>

    2.web.xml添加shiro过滤器

    <!-- 
        1. 配置  Shiro 的 shiroFilter.  
        2. DelegatingFilterProxy 实际上是 Filter 的一个代理对象. 默认情况下, Spring 会到 IOC 容器中查找和 
        <filter-name> 对应的 filter bean. 也可以通过 targetBeanName 的初始化参数来配置 filter bean 的 id. 
        -->
        <filter>
            <filter-name>shiroFilter</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            <init-param>
                <param-name>targetFilterLifecycle</param-name>
                <param-value>true</param-value>
            </init-param>
           <!--  <init-param>    
                <param-name>targetBeanName</param-name>    
                <param-value>abc</param-value>    
            </init-param>  -->
        </filter>
        <filter-mapping>
            <filter-name>shiroFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

    3.配置spring-shiro.xml配置文件

    <?xml version="1.0" encoding="UTF-8"?>  
    <beans xmlns="http://www.springframework.org/schema/beans"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">  
        
       <!--  
        1. 配置 SecurityManager!
        -->     
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="cacheManager" ref="cacheManager"/>
            <property name="authenticator" ref="authenticator"></property>
            
            <property name="realms">
                <list>
                    <ref bean="jdbcRealm"/>
                    <!-- <ref bean="secondRealm"/> -->
                </list>
            </property>
            
            <property name="rememberMeManager.cookie.maxAge" value="10"></property>
        </bean>
    
       
        <!--  
        2. 配置 CacheManager. 
        2.1 需要加入 ehcache 的 jar 包及配置文件. 
        -->     
        <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
            
            <property name="cacheManagerConfigFile" value="classpath:ehcache/ehcache.xml"/> 
        </bean>
        
        <bean id="authenticator" 
            class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
            <property name="authenticationStrategy">
                <bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>
            </property>
        </bean>
    
        
        <!-- 
            3. 配置 Realm 
            3.1 直接配置实现了 org.apache.shiro.realm.Realm 接口的 bean
        -->     
        <bean id="jdbcRealm" class="com.shenqz.shiro.realms.ShiroRealm">
            <property name="credentialsMatcher">
                <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                    <property name="hashAlgorithmName" value="MD5"></property>
                    <property name="hashIterations" value="1024"></property>
                </bean>
            </property>
        </bean>
        
        <!-- <bean id="secondRealm" class="com.shenqz.shiro.realms.SecondRealm">
            <property name="credentialsMatcher">
                <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                    <property name="hashAlgorithmName" value="SHA1"></property>
                    <property name="hashIterations" value="1024"></property>
                </bean>
            </property>
        </bean> -->
    
        
        <!--  
        4. 配置 LifecycleBeanPostProcessor. 可以自定的来调用配置在 Spring IOC 容器中 shiro bean 的生命周期方法. 
        -->       
        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    
        <!-- Enable Shiro Annotations for Spring-configured beans.  Only run after
             the lifecycleBeanProcessor has run: -->
        <!--  
        5. 启用 IOC 容器中使用 shiro 的注解. 但必须在配置了 LifecycleBeanPostProcessor 之后才可以使用. 
        -->     
        <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
              depends-on="lifecycleBeanPostProcessor"/>
        <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
            <property name="securityManager" ref="securityManager"/>
        </bean>
    
        
        <!--  
        6. 配置 ShiroFilter. 
        6.1 id 必须和 web.xml 文件中配置的 DelegatingFilterProxy 的 <filter-name> 一致.
                          若不一致, 则会抛出: NoSuchBeanDefinitionException. 因为 Shiro 会来 IOC 容器中查找和 <filter-name> 名字对应的 filter bean.
        -->     
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager"/>
            <property name="loginUrl" value="/login.jsp"/>
            <property name="successUrl" value="/WEB-INF/jsp/list.jsp"/>
            <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
            
            <property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>
            
            <!--  
                配置哪些页面需要受保护. 
                以及访问这些页面需要的权限. 
                1). anon 可以被匿名访问
                2). authc 必须认证(即登录)后才可能访问的页面. 
                3). logout 登出.
                4). roles 角色过滤器
            -->
            <!--  
            <property name="filterChainDefinitions">
                <value>
                    /login.jsp = anon
                    /shiro/login = anon
                    /shiro/logout = logout
                    
                    /user.jsp = roles[user]
                    /admin.jsp = roles[admin]
                    
                    # everything else requires authentication:
                    /** = authc
                </value>
            </property>
            -->
        </bean>
        
        <!-- 配置一个 bean, 该 bean 实际上是一个 Map. 通过实例工厂方法的方式 -->
        <bean id="filterChainDefinitionMap" 
            factory-bean="filterChainDefinitionMapBuilder" factory-method="buildFilterChainDefinitionMap"></bean>
        
        <bean id="filterChainDefinitionMapBuilder" class="com.shenqz.shiro.factory.FilterChainDefinitionMapBuilder"></bean>
        
        <bean id="shiroService" class="com.shenqz.shiro.service.ShiroService"></bean>
    
    </beans>

    4.配置spring-ehcache.xml

    <?xml version="1.0" encoding="UTF-8"?>  
    <beans xmlns="http://www.springframework.org/schema/beans"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:cache="http://www.springframework.org/schema/cache"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/cache
            http://www.springframework.org/schema/cache/spring-cache.xsd">  
    
        
        <!-- Spring提供的基于的Ehcache实现的缓存管理器 --> 
        
        <!-- 如果有多个ehcacheManager要在bean加上p:shared="true" -->
        <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
            <property name="configLocation" value="classpath:ehcache/ehcache.xml"/>
        </bean>
        
        <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
            <property name="cacheManager" ref="ehcacheManager"/>
            <property name="transactionAware" value="true"/>
        </bean>
        
        <!-- cache注解,和spring-redis.xml中的只能使用一个 -->
        <cache:annotation-driven cache-manager="cacheManager" proxy-target-class="true"/>
    </beans>  

    5.在applicationContext.xml文件中引入spring-shiro.xml文件

    <import resource="classpath:spring/spring-shiro.xml"/>

    6.编写FilterChainDefinitionMapBuilder类

    package com.shenqz.shiro.factory;
    
    import java.util.LinkedHashMap;
    
    public class FilterChainDefinitionMapBuilder {
    
        public LinkedHashMap<String, String> buildFilterChainDefinitionMap(){
            LinkedHashMap<String, String> map = new LinkedHashMap<>();
            //key表示访问的路径,页面,value代表对应的访问权限
            map.put("/js/**", "anon");
            map.put("/captcha-image.do", "anon");
            map.put("/checkCode.do", "anon");
            map.put("/login.do", "anon");
            map.put("/logout.do", "logout");
            
            map.put("/login.jsp", "anon");
            map.put("/list.jsp", "user");
            
            map.put("/**", "authc");
            
            return map;
        }
        
    }

    7.创建ShiroRealm.java类

    package com.shenqz.shiro.realms;
    
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.LockedAccountException;
    import org.apache.shiro.authc.SimpleAuthenticationInfo;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.crypto.hash.SimpleHash;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.util.ByteSource;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import com.shenqz.entity.User;
    import service.UserService;
    
    public class ShiroRealm extends AuthorizingRealm {
    
        @Autowired
        private UserService userService;
        
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(
                AuthenticationToken token) throws AuthenticationException {
            
            //1. 把 AuthenticationToken 转换为 UsernamePasswordToken 
            UsernamePasswordToken upToken = (UsernamePasswordToken) token;
            
            //2. 从 UsernamePasswordToken 中来获取 username
            String login_name = upToken.getUsername();
            User user = userService.getUserByName(login_name);
            if(user == null){
                return null;
            }
            //3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录
            System.out.println("从数据库中获取 username: " + login_name + " 所对应的用户信息.");
            
            //4. 若用户不存在, 则可以抛出 UnknownAccountException 异常
            if("unknown".equals(login_name)){
                throw new UnknownAccountException("用户不存在!");
            }
            
            //5. 根据用户信息的情况, 决定是否需要抛出其他的 AuthenticationException 异常. 
            if("monster".equals(login_name)){
                throw new LockedAccountException("用户被锁定");
            }
            
            //6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo
            //以下信息是从数据库中获取的.
            //1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象. 
            /*Object principal = username;
            //2). credentials: 密码. 
            Object credentials = null; //"fc1709d0a95a6be30bc5926fdb7f22f4";
            if("admin".equals(username)){
                credentials = "038bdaf98f2037b31f1e75b5b4c9b26e";
            }else if("test".equals(username)){
                credentials = "4292bb58be34c59d28a0dcbd11932d49";
            }*/
            
            //3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可
            String realmName = getName();
            //4). 盐值. 
            ByteSource credentialsSalt = ByteSource.Util.bytes(login_name);
            
            SimpleAuthenticationInfo info = null; //new SimpleAuthenticationInfo(principal, credentials, realmName);
            info = new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(login_name), realmName);
            return info;
        }
    
        public static void main(String[] args) {
            String hashAlgorithmName = "MD5";
            Object credentials = "123456";
            Object salt = ByteSource.Util.bytes("test");
            int hashIterations = 1024;
            
            Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
            System.out.println(result);
        }
    
        //授权会被 shiro 回调的方法
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(
                PrincipalCollection principals) {
            //1. 从 PrincipalCollection 中来获取登录用户的信息
            Object principal = principals.getPrimaryPrincipal();
            
            //2. 利用登录的用户的信息来用户当前用户的角色或权限(可能需要查询数据库)
            Set<String> roles = new HashSet<>();
            roles.add("test");
            if("admin".equals(principal)){
                roles.add("admin");
            }
            
            //3. 创建 SimpleAuthorizationInfo, 并设置其 reles 属性.
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
            info.addStringPermission("/user/add");
            //4. 返回 SimpleAuthorizationInfo 对象. 
            return info;
        }
    }

    8.对应的jsp页面设置

    <%@ page language="java" contentType="text/html; charset=UTF-8"%>
    <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>    
        
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <title>Insert title here</title>
    </head>
    <body>
        
        <h4>List Page</h4>
        
        Welcome: <shiro:principal></shiro:principal>
        <br><br>
        
        <shiro:hasRole name="admin">
            <a href="admin.jsp">Admin Page</a>
        </shiro:hasRole>
        <!-- <a href="admin.jsp">Admin Page</a> -->
        <shiro:hasRole name="test">
        <br><br>
        <a href="user.jsp">User Page</a>
        </shiro:hasRole>
        <!-- <a href="user.jsp">User Page</a> -->
        
        <shiro:hasPermission name="/user/dataGrid">
            <br><br>
            <a href="javascript:void(0)">User dataGrid</a>
        </shiro:hasPermission>
        
        <shiro:hasPermission name="/user/add">
            <br><br>
            <a href="useradd.jsp">User add</a>
        </shiro:hasPermission>
        <br>
        <a href="javascript:void(0);" onclick="getUsers();">查询用户</a>
        <br>
        <a href="getRoles.do">查询角色</a>
        <br>
        <a href="getResurces.do">查询功能</a>
        
        <br><br>
        <a href="testShiroAnnotation.do">Test ShiroAnnotation</a>
        
        <br><br>
        <a href="logout.do">Logout</a>
        <br>
        <div id="d2">
            <table id="t2">
            
            </table>
        </div>
    </body>
    </html>
    <script type="text/javascript" src="js/jquery-1.8.3.js"></script>
    <script type="text/javascript">
        function getUsers(){
            $("post","getUsers.do",function(data){
                var data=JSON.parse(data);
                var str;
                str+="<tr><td>人员编号</td><td>人员姓名</td>年龄<td></td><td>联系电话</td></tr>"
                $.each(data,function(k){
                    str+="<tr><td>"+data[k].id+"</td><td>"+data[k].name+"</td><td>"+data[k].age+"</td><td>"+data[k].phone+"</td></tr>"
                });
                $("#t2").html(str);
                
            });
        }
    </script>
  • 相关阅读:
    菜鸟小结
    计算几何题目整理(转)
    poj 3299 Humidex
    基于C的文件操作(转)
    poj 1328 Radar Installation
    poj 1321 棋盘问题(dfs)
    poj 3302 Subsequence
    C# 资产(Property) 与普通字段(field)变量的区别
    Jumping into Cloud, Be Sure You Know How to Get Out
    关于语言的想法。
  • 原文地址:https://www.cnblogs.com/shenqz/p/8064594.html
Copyright © 2020-2023  润新知