Shiro簡介 Apache Shiro是Java的一個安全框架,官網為shiro.apache.org,主要場景為控制登陸,判斷用戶是否有訪問某個功能的許可權等等。 Shiro的核心功能(入門知識,只介紹前兩個) 認證 授權 會話管理 加密 引入jar包和配置web.xml 引入Shiro對應的ja ...
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:可以開發人員編寫(即認證和授權方法)
我們首先將登錄方法按照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; } }
然後編寫
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; } }
到上面以後編碼工作就完成了,剩下的就是進行配置了,首先將編寫的
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>
配置
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>
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>