談?wù)凷hiro的原理及在SSM和SpringBoot兩種環(huán)境下的使用姿勢(下篇)

在上一篇中,我已經(jīng)對Shiro中認(rèn)證和授權(quán)模塊基本認(rèn)證做了介紹,本篇主要介紹Shiro在SSM的工程中的整合使用方式和在SpringBoot工程中的使用方式。

首先是在SSM工程中的整合

之前我們在SSM工程中作為身份認(rèn)證和權(quán)限攔截的模塊是通過攔截器的方式來實現(xiàn)的?,F(xiàn)在我們?nèi)サ魯r截器,使用Shiro整合搭建工程。

  1. 首先搭建基本的SSM工程。我這里還是采用了傳統(tǒng)的SSM工程結(jié)構(gòu)。利用maven創(chuàng)建一個骨架為web的工程中,然后在pom文件中引入依賴。

  2. 配置web.xml文件,注意這里由于我們是采用Shiro作為安全模塊,所以我們這里會在web.xml中配置一個代理的Filter,這個代理的Filter由Shiro實現(xiàn)并在Spring中配置。這個Filter將會攔截我們系統(tǒng)中所有的請求,然后進(jìn)行處理。也就是起到了原來攔截器的作用。

         <!-- 這里需要配置一個Filter,將由Shiro實現(xiàn) -->
         <filter>
             <filter-name>shiroFilter</filter-name>
             <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
             <!-- 設(shè)置true由servlet容器控制filter的生命周期 -->
             <init-param>
                 <param-name>targetFilterLifecycle</param-name>
                 <param-value>true</param-value>
             </init-param>
             <!-- 設(shè)置spring容器filter的bean id,如果不設(shè)置則找與filter-name一致的bean-->
             <init-param>
                 <param-name>targetBeanName</param-name>
                 <param-value>shiroFilter</param-value>
             </init-param>
         </filter>
         <filter-mapping>
             <filter-name>shiroFilter</filter-name>
             <url-pattern>/*</url-pattern>
         </filter-mapping>
    
  3. 在src/main/resources中引入db.properties和Mybatis的配置文件SqlMapConfig.xml。然后我們對工程中進(jìn)行MyBatis配置。

         <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-config.dtd">
         <configuration>
             <!-- 定義 別名 -->
             <typeAliases>
                 <package name="com.beautifulsoup.shiro.ssmdemo.entity"/>
             </typeAliases>
         </configuration>
    
  4. 配置Spring的環(huán)境和SpringMVC的環(huán)境。在src/main/resources目錄下創(chuàng)建spring目錄,然后依次創(chuàng)建applicationContext-dao.xml,applicationContext-service.xml,applicationContext-trans.xml,springmvc.xml文件。之后在這些文件中進(jìn)行SSM框架整合的配置。

  5. 在第3步的spring目錄下創(chuàng)建一個applicationContext-shiro.xml的配置文件,我們在web.xml中配置所需的Filter將在這里注冊。
    首先在web.xml中我們已經(jīng)指定了filter bean的名字是shiroFilter,所以我們注冊的filter的beanname也應(yīng)該是shiroFilter。此外,在上一篇的基本介紹中我們也知道了,Shiro中的核心是SecurityManager,SecurityManager最終交給Realm進(jìn)行認(rèn)證和授權(quán),所以這些我們也應(yīng)該在Spring配置文件中配置,交給Spring容器管理。

                <!-- 配置Realm -->
                <bean id="shiroDemoRealm" class="com.beautifulsoup.shiro.ssmdemo.realm.ShiroDemoRealm"/>
                <!-- 配置安全管理器 -->
                <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
                    <property name="realm" ref="shiroDemoRealm" />
                </bean>
                <!-- Shiro 的Web過濾器 -->
                <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
                    <property name="securityManager" ref="securityManager" />
                    <!-- 如果沒有認(rèn)證將要跳轉(zhuǎn)的登陸地址 -->
                    <property name="loginUrl" value="/login.action" />
                    <!-- 沒有權(quán)限跳轉(zhuǎn)的地址 -->
                    <property name="unauthorizedUrl" value="/refuse.jsp" />
                    <property name="filterChainDefinitions">
                        <value>
                            /** = anon
                        </value>
                    </property>
                </bean>

為了簡單,我直接使用了上一次所介紹的realm類。

可以看到,這里我們主要是配置了一個ShiroFilterFactoryBean,這是一個工廠類,它主要用于生產(chǎn)ShiroFilter,我們可以在這個工廠Bean中定義一系列我們所需要的Filter鏈。Shiro這個框架本身就為我們提供了很多的過濾器,通過使用這些已經(jīng)內(nèi)置的過濾器已經(jīng)能夠很好的實現(xiàn)我們所需要實現(xiàn)的功能。上面我們配置的/**=anon表示對于該工程中所有的url都可以以匿名的方式來訪問,anon表示一個過濾器的縮寫,除此之外,Shiro還提供了其他的一系列的過濾器。如下:

        過濾器簡稱   對應(yīng)的實際過濾器
        anon    org.apache.shiro.web.filter.authc.AnonymousFilter
        authc   org.apache.shiro.web.filter.authc.FormAuthenticationFilter
        authcBasic  org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
        perms   org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
        port    org.apache.shiro.web.filter.authz.PortFilter
        rest    org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
        roles   org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
        ssl org.apache.shiro.web.filter.authz.SslFilter
        user    org.apache.shiro.web.filter.authc.UserFilter
        logout  org.apache.shiro.web.filter.authc.LogoutFilter

接下來,我們就通過這些攔截器來實現(xiàn)我們SSM工程的認(rèn)證和授權(quán)。

認(rèn)證
代碼在(v0.3標(biāo)簽下)
登錄和退出:
配置如下:

        <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
            <property name="hashAlgorithmName" value="md5"/>
            <property name="hashIterations" value="3"/>
        </bean>
        <bean id="shiroDemoRealm" class="com.beautifulsoup.shiro.ssmdemo.realm.ShiroDemoRealm">
            <property name="credentialsMatcher" ref="credentialsMatcher"></property>
        </bean>
        <!-- 配置安全管理器 -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="shiroDemoRealm" />
        </bean>
        <!-- Shiro 的Web過濾器 -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager" />
            <!-- 如果沒有認(rèn)證將要跳轉(zhuǎn)的登陸地址 -->
            <property name="loginUrl" value="/login.action" />
            <!-- 沒有權(quán)限跳轉(zhuǎn)的地址 -->
            <property name="unauthorizedUrl" value="/refuse.jsp" />
            <property name="filterChainDefinitions">
                <value>
                    <!-- 定義退出的路徑 -->
                    /logout.action = logout
                    /** = authc                 
                </value>
            </property>
        </bean>

主要通過FormAuthenticationFilter實現(xiàn)。這里需要注意的是,我們提交認(rèn)證的表單的參數(shù)默認(rèn)為username和password,記住我的參數(shù)默認(rèn)為:rememberMe。原因如下:

Aaron Swartz

注意,當(dāng)我們在系統(tǒng)中采用FormAuthenticationFilter作為配置時,FormAuthenticationFilter會將表單的提交參數(shù)取出,并調(diào)用realm進(jìn)行認(rèn)證。如果認(rèn)證失敗,則系統(tǒng)自動跳轉(zhuǎn)到我們配置的loginUrl的鏈接地址,同時會將認(rèn)證失敗的異常信息添加到request中,我們可以在Controller中定義一個方法接受loginUrl配置的鏈接地址,然后從中取出異常信息進(jìn)行二次處理。而如果我們認(rèn)證成功了,系統(tǒng)的成功處理器會默認(rèn)跳轉(zhuǎn)到我們將要訪問的url路徑。我們可以使用類似loginUrl的配置配置一個successUrl實現(xiàn)自定義的成功跳轉(zhuǎn)邏輯。

授權(quán):

代碼在v0.4標(biāo)簽下

上面提到了,Shiro的web模塊主要是為我們提供了一系列的過濾器Filter,在傳統(tǒng)的ssm項目整合過程中,我們是通過將Shiro交給Spring進(jìn)行管理然后在容器中配置一個過濾器鏈。

上面提到的認(rèn)證是通過配置過濾器FormAuthenticationFilter完成的,這里的授權(quán)是通過配置PermissionsAuthorizationFilter完成的。

配置如下:

        <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
            <property name="hashAlgorithmName" value="md5"/>
            <property name="hashIterations" value="3"/>
        </bean>
        <bean id="shiroDemoRealm" class="com.beautifulsoup.shiro.ssmdemo.realm.ShiroDemoRealm">
            <property name="credentialsMatcher" ref="credentialsMatcher"></property>
        </bean>
        <!-- 配置安全管理器 -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="shiroDemoRealm" />
        </bean>
        <!-- Shiro 的Web過濾器 -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager" />
            <!-- 如果沒有認(rèn)證將要跳轉(zhuǎn)的登陸地址 -->
            <property name="loginUrl" value="/login.action" />
            <!-- 沒有權(quán)限跳轉(zhuǎn)的地址 -->
            <property name="unauthorizedUrl" value="/refuse.action" />
            <property name="filterChainDefinitions">
                <value>
                    <!-- 定義所需的權(quán)限信息 -->
                    /item/query.action=perms[item:query]
                    /item/delete02.action=perms[item:delete:02]
                    <!-- 定義退出的路徑 -->
                    /logout.action = logout
                    /** = authc                 
                </value>
            </property>
        </bean>

除了xml中的配置,shiro還提供了注解的授權(quán)的方法。由于注解的授權(quán)方式本質(zhì)上是Spring的AOP的代理方式,所以我們需要在Spring的配置文件中開啟AOP的支持。:

        <aop:config proxy-target-class="true"></aop:config>
        <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
            <property name="securityManager" ref="securityManager" />
        </bean>
        
        在Controller中使用
        
        @RequestMapping("/delete02")
        @RequiresPermissions("item:delete:02")
        public String itemDelete(){
            
            
            return "delete02item";
        }
        
        @RequiresPermissions("item:query")
        @RequestMapping("/query")
        public String ItemQuery(){
            return "itemquery";
        }

我們在每次查詢權(quán)限信息的時候,控制臺總會彈出警告:

Aaron Swartz

這是提示我們沒有添加緩存,這會使得我們頻繁查詢數(shù)據(jù)庫導(dǎo)致效率低下。在上一節(jié)的基本概念中也已經(jīng)提到過幾個重要的概念,其中CacheManager就是實現(xiàn)緩存管理的,SessionManager是實現(xiàn)的Session的管理。

這里我們使用Shiro整合EhCache來實現(xiàn)緩存的管理。

    <!-- 緩存管理器 -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
    </bean>
    
    ehcache的配置文件:
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
        <!--diskStore:緩存數(shù)據(jù)持久化的目錄 地址  -->
        <diskStore path="D:\Temp" />
        <defaultCache 
            maxElementsInMemory="1000" 
            maxElementsOnDisk="10000000"
            eternal="false" 
            overflowToDisk="false" 
            diskPersistent="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120" 
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        </defaultCache>
    </ehcache>

Shiro在SSM傳統(tǒng)工程中的整合工程大多就這些,下面簡單說一下關(guān)于SpringBoot整合Shiro的使用方式。

然后是在SpringBoot工程中的整合:

SpringBoot是對Spring傳統(tǒng)項目的簡化,自然Shiro與SpringBoot的整合也是Shiro與Spring整合的簡化。SpringBoot與Shiro的整合類似于SSM工程與Shiro的整合。這里只介紹關(guān)于整合的不同之處。對于SSM的整合和SpringBoot整合的完整代碼都已經(jīng)上傳Github。

    主要是將原來的XML中的配置提取到了Java配置中,核心的Java Config的類如下:
        @Bean("credentialMatcher")
        public CredentialMatcher credentialMatcher(){
            return new CredentialMatcher();
        }
    
        @Bean("authRealm")
        public AuthRealm authRealm(@Qualifier("credentialMatcher")CredentialMatcher matcher){
            AuthRealm authRealm=new AuthRealm();
            authRealm.setCredentialsMatcher(matcher);
            return authRealm;
        }
    
        @Bean("securityManager")
        public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm){
            DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
            securityManager.setRealm(authRealm);
            return securityManager;
        }
    
        @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")SecurityManager securityManager){
            ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            shiroFilterFactoryBean.setLoginUrl("/login");
            shiroFilterFactoryBean.setSuccessUrl("/index");
            shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
    
            LinkedHashMap<String,String> filterChainDefinitionMap=new LinkedHashMap<>();
            filterChainDefinitionMap.put("/login","anon");
            filterChainDefinitionMap.put("/index","authc");
            filterChainDefinitionMap.put("/loginUser","anon");
            //filterChainDefinitionMap.put("/**","user");//配置shiro只要用戶登錄就可以查看所有url
            filterChainDefinitionMap.put("/admin", "roles[role3]");
            filterChainDefinitionMap.put("/edit", "perms[item:create:01]");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            return shiroFilterFactoryBean;
        }
    
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager")SecurityManager securityManager){
            AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager);
            return advisor;
        }
    
        @Bean
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
            DefaultAdvisorAutoProxyCreator creator=new DefaultAdvisorAutoProxyCreator();
            creator.setProxyTargetClass(true);
            return creator;
        }

這里可以看到,其實SpringBoot中我們完全可以使用Java配置替代XML配置,具體的整合思路還是一樣的。

最后:

SSM整合Shiro的代碼地址:https://github.com/fuyunwang/SSMShiro.git

SpringBoot整合Shiro的代碼地址:https://github.com/fuyunwang/SpringBootShiro.git

如果對您有過幫助,希望您隨手一個star。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容