Apache Shiro介紹與使用

什麼是shiro?

借用官方的話

Apache Shiro是一種功能強大且易於使用的Java安全框架,可執行身份驗證,授權,加密和會話管理,可用於保護任何應用程序的安全-從命令行應用程序,移動應用程序到最大的Web和企業應用程序。

Shiro提供了用於執行以下方面的應用程序安全性API(我將其稱爲應用程序安全性的4個基石):

  • 身份驗證-證明用戶身份,通常稱爲用戶“登錄”。
  • 授權-訪問控制
  • 密碼學-保護或隱藏數據以防窺視
  • 會話管理-每個用戶的時間敏感狀態

Shiro還支持一些輔助功能,例如Web應用程序安全性,單元測試和多線程支持,但它們的存在是爲了加強上述四個主要方面。

 

現在使用比較多的安全權限框架還有spring家族的Spring Security,與Spring Security 相比 shiro可能沒有 Spring Security 做的功能強大,但是在實際工作時 可能並不需要那麼複雜的東西,所以使用小而簡單的Shiro 就足夠了。

Apache Shiro的優點

自2003年以來,框架環境發生了很大變化,因此今天仍然有充分的理由使用Shiro。實際上有很多原因。Apache Shiro是:

  • 易於使用 -易於使用是該項目的最終目標。應用程序安全性可能非常令人困惑和沮喪,並被視爲“必要的邪惡”。如果您使它易於使用,以使新手程序員可以開始使用它,那麼就不必再痛苦了。
  • 全面 -Apache Shiro聲稱沒有其他具有範圍廣度的安全框架,因此它很可能是滿足安全需求的“一站式服務”。
  • 靈活 -Apache Shiro可以在任何應用程序環境中工作。儘管它可以在Web,EJB和IoC環境中運行,但並不需要它們。Shiro也不要求任何規範,甚至沒有很多依賴性。
  • 具有Web功能 -Apache Shiro具有出色的Web應用程序支持,允許您基於應用程序URL和Web協議(例如REST)創建靈活的安全策略,同時還提供一組JSP庫來控制頁面輸出。
  • 可插拔 -Shiro乾淨的API和設計模式使它易於與許多其他框架和應用程序集成。您會看到Shiro與Spring,Grails,Wicket,Tapestry,Mule,Apache Camel,Vaadin等框架無縫集成。
  • 支持 -Apache Shiro是Apache Software FoundationApache軟件基金會)的一部分,該組織被證明以其社區的最大利益行事。項目開發和用戶羣體友好的公民隨時可以提供幫助。如果需要,像Katasoft這樣的商業公司也可以提供專業的支持和服務。

簡而言之,就是輕量級,小巧方便,易於使用,能與衆多框架無縫集成。

shiro使用

shiro的驗證流程

認證流程

 

在執行調用subject.login(token)方法後,會把subject以及token都傳進去
(subject是從環境中取出的,也就是說subject是可以代表當前用戶所處的上下文環境,也即是說可以拿到當前環境的realm的真實數據);程序會先判斷賬號,再判斷密碼。

示例:與spring無縫集成

第一步導入相關shiro框架jar包,或引入shiro依賴

第二步配置spring配置文件

  • 把這個filter交給Spring管理,通過ShiroFilterFactoryBean來創建這個ShiroFilter。裏面可配置(anon,logout,authc)等多個過濾器。

  • 配置好了過濾器,再不妨想想在JavaSE中我們是怎麼進行登錄認證的?
    我們先是進行安全管理器的設置,告知當前環境用的是什麼管理器,所以我們也需要在spring中配置安全管理器。上面講到,通過源碼分析發現自定義數據源是在創建securityManager實例對象時加載的,所以在spring配置
    securityManager的時候,我們要告知安全管理器是用哪個數據源。配置property

  • 過濾中執行認證操作
    過濾功能有了,認證功能也有了此時我們就是需要在過濾的時候進行認證操作,也就是結合這個兩個功能,這是隻需要將filter和securityManager配置關聯即可

<!--注意:名字必須要和web.xml中配置的名字一致-->
    <!-- 定義ShiroFilter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <property name="loginUrl" value="/login.html"/>
    <property name="filterChainDefinitions">
        <value>
            /js/**=anon
            /bootstrap-3.3.7-dist/**=anon
            /jQuery/**=anon
            /images/**=anon
            /css/**=anon
            /style/**=anon
            /logout.do=logout
            /**=authc
        </value>
     </property>
    <property name="filters">
        <map>
            <entry key="authc" value-ref="myCRMFormFilter"/>
        </map>
    </property>
</bean>

<!-- 配置安全管理器SecurityManager 在web環境下使用默認web安全管理器-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="myWebRealm"/>
</bean>

 

授權操作

//授權
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    //創建一個空的AuthorizationInfo
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //拿到當前用戶
    Employee employee = (Employee)principalCollection.getPrimaryPrincipal();
    //判斷是否是超級管理員
    if(employee.getAdmin()){
        //給管理員設置用戶信息,並且可以查詢所有權限
        info.addRole("admin");
        info.addStringPermission("*:*");
        return info;
    }else{
        //從數據庫中查到所對應的角色和權限
        List<String> roles = employeeService.getRolesByEmployeeId(employee.getId());
        Set<String> permissions = employeeService.getPermissionsByEmployeeId(employee.getId());
        info.addRoles(roles);
        info.addStringPermissions(permissions);
        return info;
    }
}

就像我們之前做RBAC的一樣,既然要有權限控制,那麼資源所對應的權限是我們規定的。

  • 加載權限
    加載權限也是將Controller中貼有註解(@RequiresPermissions)的方法掃描出來存進數據庫中,同樣也是通過注入的方式拿到Spring容器對象
    不同點在於:
  • 使用Shiro時,使用容器對象的getBeansWithAnnotation()獲得的controller是可以包括貼有@Controller註解的類的子類的 (這裏的意思是說,Shrio會自動將貼有標籤的Controller類動態生成相應的代理類,而@Controller這個註解是沒有繼承的,但是SpringMVC還是能查找到,並且如果有子類只會找子類而不會找其父類) 然後我們要判斷這些字節碼對象是否是屬於cglib的代理類 (AopUtils.isCglibProxy(controller))

  • 再用這些判斷後的字節碼對象獲得其父類字節碼(controller.getClass().getSuperclass())(@RequiresPermissions標籤不繼承)找到貼有這些註解的方法,獲取其方法體上的註解字節碼然後拿到內容,存進數據庫中

  • 取出權限並存入作用域中
    使用Shiro可以很方便的做到這一步,
    就像上面說的,只需要通過principalCollection.getPrimaryPrincipal()拿到當前身份信息,也就是認證過的用戶,然後把權限從數據庫查到,丟到info即可
    與原來RBAC的不同在於
    RBAC需要是用RequestContextHolder.getRequestAttributes()方法拿到session,然後再丟進session,這樣其實很麻煩

總的來說

Shiro是先進行認證,認證通過後進行授權,什麼時候校驗權限?訪問方法的時候,代理類增強的方法會去檢驗。

MD5加密

在認證的時候會用到MD5加密,因爲存進數據庫的密碼是通過加密的,而用戶登錄表單傳過來的密碼也要相同規則加密纔行,這時我們在數據源中只將鹽丟進info裏面,讓shiro後續進行加密即可,那麼實行什麼方式的加密是我們配置的,在shiro.xml中配置,然後配置給自定義中的setCredentialsMatcher方法

<!--配置憑證匹配器,並將其設置給realm(通過注入的方式)-->
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
    <property name="hashAlgorithmName" value="md5"/>
</bean>

 

在使用shiro驗證權限時,因爲是shiro自動生成的動態代理類,使用的AoP織入,所以我們要加上AoP的配置(事務時已經加過了),又因爲在功能加強中要知道當前的安全管理器,才能獲取到數據源等信息,所以我們需要指明數據源

<!--配置權限AoP織入增強功能-->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
    <property name="securityManager" ref="securityManager"/>
</bean>

緩存管理器

使用shiro自帶的緩存管理器,這時權限和角色信息(shrio只負責這兩塊,所以也只緩存這兩塊,不需另外指明)緩存到內存中,這樣就不會刷新頁面訪問同樣的資源時還要執行數據源中的授權方法,這樣就不用再發SQL了

<!-- 緩存管理器開始 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    <property name="cacheManager" ref="ehCacheManager"/>
</bean>
<bean id="ehCacheManager" class ="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    <property name="configLocation" value="classpath:shiro-ehcache.xml" />
    <property name="shared" value="true"/>
</bean>

以上就是關於shiro的基本介紹與使用

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章