安全框架Shiro入門


Shiro簡介

Apache Shiro是Java的一個安全框架,官網為shiro.apache.org,主要場景為控制登陸,判斷用戶是否有訪問某個功能的權限等等。

Shiro的核心功能(入門知識,只介紹前兩個)

  • 認證

  • 授權

  • 會話管理

  • 加密

引入jar包和配置web.xml

  • 引入Shiro對應的jar包,下面給出Maven

    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-all</artifactId>
        <version>1.2.2</version>
    </dependency>
    
    
  • 在web.xml中配置spring框架提供的用於整合shiro框架的過濾器

    	<!-- 配置shiro過濾器 -->
    <filter>
    	<filter-name>shiroFilter</filter-name>	  // 需要在spring的配置文件中創建一個bean(shiroFilter)
    	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>	
    </filter>
    <filter-mapping>
    	<filter-name>shiroFilter</filter-name>
    	<url-pattern>/*</url-pattern>
    </filter-mapping>
    

下面我們將要進行Shiro的認證功能和授權功能的實現,代碼比較多。

登錄方法的實現

Shiro認證的流程

  • Application Code:應用程序代碼, 即登錄方法(登錄方法不是直接查詢數據庫,而是調用Shiro框架提供的接口來實現)

  • Subject:框架提供的接口,代表當前用戶對象

  • SecurityManager:框架提供的接口,代表安全管理器對象

  • Realm:可以開發人員編寫(即認證和授權方法)

  1. 我們首先將登錄方法按照Shiro指定的方式進行改進

     public String login() {
      	// 獲取驗證碼
        String validateCode = (String) ServletActionContext.getRequest().getSession().getAttribute("key");
        // 判斷驗證碼
        if (StringUtils.isNotBlank(checkcode) && checkcode.equals(validateCode)) {  
        	// 獲取getSubject對象,Shiro中代表當前用戶對象
            Subject subject = SecurityUtils.getSubject();
    
            // 令牌 傳遞進去前台接受的賬號和密碼
            AuthenticationToken token = new UsernamePasswordToken(model.getUsername(),
                    MD5Utils.md5(model.getPassword()));// 創建用戶名密碼令牌對象
            try {
                subject.login(token); // 調用內置的登錄方法來實現檢驗 如果登陸錯誤就會拋出異常,返回登錄頁面
            } catch (Exception e) {
                e.printStackTrace();
                return LOGIN;
            }
            User user = (User) subject.getPrincipal();   // 登錄成功后可以從subject取得登錄對象
            ServletActionContext.getRequest().getSession().setAttribute("loginUser", user);
            return HOME;
    
        } else {
            this.addActionError("輸入驗證碼錯誤");
            return LOGIN;
        }
    
    }
    
    
  2. 然后編寫Realm繼承AuthorizingRealm ,即編寫具體的認證和授權方法

        public class BOSRealm extends AuthorizingRealm {
        @Autowired
        private IUserDao userDao
    
        // 授權方法
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
        	// 可以在這里將用戶所屬的權限查詢出來,然后遍歷賦值給info對象,這樣就可以實現了授權
        	// 判斷訪問路徑或者方法有沒有權限的時候就是根據info中的數據來判斷
            info.addStringPermission("staff-list");
            return info;
        }
        // 認證方法(登陸方法)
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
            System.out.println("認證...");
            UsernamePasswordToken passwordToken = (UsernamePasswordToken) arg0;   // 對象轉換
            String username = passwordToken.getUsername();   // 獲得username
            User user = userDao.findByUsername(username);    // 通過username從數據庫中獲取到User對象
            if (user == null) {
                return null;
            }
            // 內置驗證方法 (數據庫中獲取的對象,對象的密碼, this.getName())
            AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());  
            return authenticationInfo;
        }
    
    }
    
  3. 到上面以后編碼工作就完成了,剩下的就是進行配置了,首先將編寫的Realm注入到安全管理器,整合的是Spring,所以下面的配置都是在Spring配置文件中。

    <!-- 注冊realm -->
    <bean id="bosRealm" class="lyh.bos.realm.BOSRealm"></bean>
    
    <!-- 注冊安全管理器對象 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    	<property name="realm" ref="bosRealm"/>
    </bean>
    
    
  4. 配置ShiroFilterFactoryBean,同時還可以配置一下URL攔截規則,注意這里的id要和web.xml<filter-name>shiroFilter</filter-name>相同

    <!-- shiro 配置 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  <!-- 此處為web.xml配置的攔截器 -->
    	<!-- 注入安全管理器對象 -->
    	<property name="securityManager" ref="securityManager"/>   
    	<!-- 注入相關頁面訪問URL -->
    	<property name="loginUrl" value="/login.jsp"/>          <!-- 登錄頁面 -->
    	<property name="successUrl" value="/index.jsp"/>   <!-- 登錄成功的主頁 -->
    	<property name="unauthorizedUrl" value="/unauthorized.jsp"/>   <!-- 權限不足轉向的錯誤頁面 -->
                <property name="unauthorizedUrl" value="/unauthorized.jsp"/> 
    	<!--注入URL攔截規則, -->
    	<!-- anon 都可以訪問   
                       perms["staff-list"] 是否有staff-list權限 
                       authc 登錄才可以訪問 -->
    	<property name="filterChainDefinitions">  
    		<value>
    			/css/** = anon
    			/admin/logout = logout    <!-- 注銷,訪問這個路徑,自動注銷不需要自己編寫方法 -->
    			/images/** = anon
    			/validatecode.jsp* = anon
    			/login.jsp = anon
    			/userAction_login.action = anon
    			/page_base_staff.action = perms["staff-list"]   <!-- 表示page_base_staff.action路徑需要有staff-list權限才可訪問 -->
    			/* = authc    
    		</value>
    	</property>
    </bean>
    
    
  5. Shiro還提供了使用注解控制權限的方法,開啟方式如下,同時,使用的注解權限還需要配置全局異常,用來捕獲當權限不足拋出異常時轉向的頁面,這里使用的是SpringMVC,開啟方式@RequiresPermissions("staff-list")

    	<!-- 開啟注解配置權限 -->
    <bean id="defaultAdvisorAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
    	<!-- 必須使用cglib方式為       Action對象創建代理對象 -->
    	<property name="proxyTargetClass" value="true"/>
    </bean>
    
    <!-- 配置shiro框架提供的切面類,用於創建代理對象 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/> 
    
    // 配置全局異常處理器
        <!-- 需要進行權限控制的頁面訪問 -->
    <global-results>
    	<result name="login">/login.jsp</result>
    	<result name="unauthorized">/unauthorized.jsp</result>
    </global-results>
    
    <!-- 全局異常處理 -->
    <global-exception-mappings>
    	<exception-mapping result="unauthorized" exception="org.apache.shiro.authz.UnauthorizedException"></exception-mapping>
    </global-exception-mappings>
    

Shiro提供的控制權限的方式

  • URL權限攔截控制

  • 方法注解權限控制

  • 頁面標簽權限控制(當有對應的權限就顯示對應的頁面元素,沒有權限則不顯示), 需要在對應的頁面引入Shiro的標簽庫
    <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>,可以用在HTMl也可以用在JS中。

  • 代碼級別權限控制(在方法內添加代碼)

Shiro整合ehcache緩存權限數據

如果訪問一個頁面就執行一次授權,就會訪問數據庫,浪費資源,所以我們可以使用ehcache來進行緩存權限,只要登錄時進行一次授權,后面無需再次授權,直接使用緩存。

shiro自動整合ehcache,只需要簡單配置就能使用。

  • 在根目錄下建立ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
            maxElementsInMemory="10000"    
            eternal="false"
            timeToIdleSeconds="600"
            timeToLiveSeconds="600"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />
 
    <!-- 
    	內存中最多可以存儲多少個數據 
    	是否永久有效
    	空閑時間
    	存活時間
		內存空間不夠是否存儲到磁盤
    	磁盤最大存儲個數
    	服務器重啟,磁盤數據是否需要
    	線程
      	淘汰策略(最近最少使用)  
     -->  
</ehcache>
  • 在spring配置文件中配置緩存管理器對象,並注入給安全管理器對象
        <!-- 注冊ehcache -->
	<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
		<property name="cacheManagerConfigFile" value="classpath:ehcache.xml" />
	</bean>
  • 將ehcache注入到shiro的配置管理器,shiro會自動使用緩存管理,在原來的管理器中添加<property name="cacheManager" ref="cacheManager"/> 一條語句即可。
        <!-- 注冊安全管理器對象 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="bosRealm"/>
		<!-- 將ehcache注入shiro -->
		<property name="cacheManager" ref="cacheManager"/>
	</bean>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM