Shiro+SSM基本使用

一、Shiro功能

  • Authentication:身份認證/登錄

  • Authorization:授權(權限驗證)

  • Session Manager:會話管理,會話可以是Java SE環境也可以是Java EE環境。使用Shiro,在service層和dao層也可以直接活動session對象,實現解耦

  • Cryptography:加密

  • Caching:緩存,比如用戶登錄後,其用戶用於的角色/權限不必每次去查

  • Run As:允許一個用戶假如另一個用戶的身份進行訪問

  • Remember Me:記住我

二、Shiro架構

在這裏插入圖片描述

在這裏插入圖片描述

1、緩存管理器

  • 內置的緩存管理器:org.apache.shiro.cache.MemoryConstrainedCacheManager
  • Ehcache管理器:org.apache.shiro.cache.ehcache.EhCacheManager
  • redis緩存管理器:org.crazycake.shiro.RedisCacheManager

三、SSM整合shiro

1、pom.xml

<shiro.version>1.4.2</shiro.version>
<commons-collections.version>3.2.1</commons-collections.version>
<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-quartz</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>
		<dependency>
		    <groupId>commons-collections</groupId>
		    <artifactId>commons-collections</artifactId>
    		<version>${commons-collections.version}</version>
		</dependency>	

2、web.xml

	<!-- shiro的攔截器 -->
	<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>
	</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:util="http://www.springframework.org/schema/util"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

	<!-- 緩存管理器 使用shiro內置的緩存 還可以使用ehcache和redis緩存 -->
	<bean id="shiroCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"></bean>
	
	
	<!-- 憑證匹配器 -->
	<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
		<!-- 加密算法名稱 -->
		<property name="hashAlgorithmName" value="MD5"></property>
		<!-- 加密次數 -->
		<property name="hashIterations" value="10"></property>
	</bean>
	
	
	<!-- Realm實現 -->
    <bean id="userRealm" class="com.bs.shiro.realm.ShiroRealm">
        <!-- 使用credentialsMatcher實現密碼驗證服務 -->
        <property name="credentialsMatcher" ref="credentialsMatcher"/>
        <!-- 是否啓用緩存 -->
        <property name="cachingEnabled" value="true"/>
        <!-- 啓用認證緩存 -->
        <property name="authenticationCachingEnabled" value="true"/>
        <!-- 緩存AuthenticationInfo信息的緩存名稱 -->
        <property name="authenticationCacheName" value="authenticationCache"/>
        <!-- 啓用授權緩存 -->
        <property name="authorizationCachingEnabled" value="true"/>
        <!-- 緩存AuthorizationInfo信息的緩存名稱 -->
        <property name="authorizationCacheName" value="authorizationCache"/>
    </bean>
    
    
    <!-- 會話Cookie模板 -->
    <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg value="sid"/>
        <!-- 如果設置爲true,則客戶端不會暴露給服務端腳本代碼,有助於減少某些類型的跨站腳本攻擊 -->
        <property name="httpOnly" value="true"/>
        <property name="maxAge" value="-1"/><!-- maxAge=-1表示瀏覽器關閉時失效此Cookie -->
    </bean>
    <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg value="rememberMe"/>
        <property name="httpOnly" value="true"/>
        <property name="maxAge" value="2592000"/><!-- 30天 -->
    </bean>
    
    
    <!-- rememberMe管理器 -->
    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
        <!-- cipherKey是加密rememberMe Cookie的密匙,默認AES算法 -->
        <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>
        <property name="cookie" ref="rememberMeCookie"/>
    </bean>
    
    
    <!-- 會話驗證調度器 -->
    <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">
        <property name="sessionValidationInterval" value="1800000"/>
        <property name="sessionManager" ref="sessionManager"/>
    </bean>
    
    
    <!-- 會話管理器 -->
    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <!-- 設置全局會話過期時間:默認30分鐘 -->
        <property name="globalSessionTimeout" value="1800000"/>
        <!-- 是否自動刪除無效會話 -->
        <property name="deleteInvalidSessions" value="true"/>
        <!-- 會話驗證是否啓用 -->
        <property name="sessionValidationSchedulerEnabled" value="true"/>
        <!-- 會話驗證調度器 -->
        <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
        <!-- 是否啓用sessionIdCookie,默認是啓用的 -->
        <property name="sessionIdCookieEnabled" value="true"/>
        <!-- 會話Cookie -->
        <property name="sessionIdCookie" ref="sessionIdCookie"/>
    </bean>
    
    
	<!--配置安全管理器 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="cacheManager" ref="shiroCacheManager" />
		<property name="sessionManager" ref="sessionManager"/>
		<property name="realm" ref="userRealm" />
		<property name="rememberMeManager" ref="rememberMeManager"/>
	</bean>
	<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
		<property name="securityManager" ref="securityManager" />
	</bean>
	
	

	<!-- 配置ShiroFilter -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<!-- 未認證時返回的頁面 被authc user logout 等認證攔截器攔截後訪問的url -->
		<property name="loginUrl" value="/user/unAuthenticated.do"/> 
		<!-- 未授權時返回的頁面 被roles 等授權攔截器攔截後訪問的url -->
		<property name="unauthorizedUrl" value="/user/unAuthorized.do"/> 
		<property name="filterChainDefinitions">
			<value>
				<!-- 可以匿名訪問 -->
				/user/login.do = anon
				
				
				<!-- 訪問該url登出 -->
				/user/logout.do = logout
				
				
				<!-- 認證或記住我後可以訪問 -->
				/user/index.do = user
				
				
				<!-- 需要授權纔可以訪問 -->
				/user/admin.do = roles[admin]
				
				
				<!-- 需要認證纔可以訪問 -->
				/** = authc
			</value>
		</property>
	</bean>
	
	
	<!-- shiro聲明週期處理器 -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
</beans>

四、Shiro使用

1、Session Manager

Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();

2、自定義realm

public class ShiroRealm extends AuthorizingRealm{
	/**
	 * 認證時會被shiro回調
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		//1、把AuthenticationToken轉換爲UsernamePasswordToken
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		//2、從UsernamePasswordToken獲取用戶名
		String userName = upToken.getUsername();
		//3、從數據庫獲取用戶信息
		String realUserName = "user";
		String realPassWord = "e4216961e03f91a7632f9fee1444d3bb";
		//4、拋出異常
		//	1)用戶不存在
		if("unknow".equals(realUserName)) {
			throw new UnknownAccountException("用戶不存在");
		}
		//	2)用戶被鎖定
		if("monster".equals(userName)) {
			throw new LockedAccountException("用戶被鎖定");
		}
		//	3)其他異常
		//throw new AuthenticationException();
		
		//5、構建AuthenticationInfo 並返回。從數據庫獲取以下信息
		//1)principal:認證的實體信息,可以是username
		Object principal = realUserName;
		//2)credentials:密碼
		Object credentials = realPassWord;
		//3)credentialsSalt:鹽值,一般用隨機字符串或用戶名(唯一值)
		ByteSource credentialsSalt = ByteSource.Util.bytes(userName);
		//4)realmName
		String realmName = getName();
		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,credentials,credentialsSalt,realmName);
		
		return info;
	}
	/**
	 * 檢測是否有授權時會被shiro回調
	 * 不用主動調用
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		//1.從PrincipalCollection中獲取登錄用戶信息
		Object principal = principals.getPrimaryPrincipal();
		//2.利用登錄用戶的信息來獲取用戶權限信息
		Set<String> roles = new HashSet<>();
		roles.add("user");
		if("admin".equals(principal)){
			roles.add("admin");
		}
		//3.創建SimpleAuthorization 並設置其reles屬性
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
		//4.返回SimpleAutorizationInfo對象
		return info;
	}
}

3、Authentication(用戶登錄相關邏輯)

		//獲得當前用戶
		Subject currentUser = SecurityUtils.getSubject();
		//如果用戶還未被認證(登錄)
		if (!currentUser.isAuthenticated()) {
			UsernamePasswordToken token = new UsernamePasswordToken(user, password);
			try {
                token.setRememberMe(true);//記住我
                currentUser.login(token);//會使用自定義的ShiroRealm來驗證登錄(在Shiro的配置文件中配置)
            } catch (UnknownAccountException uae) {
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            } catch (AuthenticationException ae) {
            	ae.printStackTrace();
            }
		}

4、Authorization

//該用戶是否爲某個角色
currentUser.hasRole("schwartz"); 
//該用戶是否有某個授權
currentUser.isPermitted("lightsaber:wield"); //對lightsaber做wield
currentUser.isPermitted("winnebago:drive:eagle5"); //對winnebago類型的eagle5對象做drive,如"user:delete:張三"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章