鍍金池/ 教程/ Java/ 與 Spring集成
綜合實例
JSP 標(biāo)簽
集成驗證碼
在線會話管理
身份驗證
攔截器機(jī)制
編碼/加密
INI 配置
單點登錄
并發(fā)登錄人數(shù)控制
OAuth2 集成
動態(tài) URL 權(quán)限控制
Realm 及相關(guān)對象
多項目集中權(quán)限管理及分布式會話
授予身份及切換身份
RememberMe
會話管理
與 Spring集成
與 Web 集成
緩存機(jī)制
簡介
授權(quán)
SSL
無狀態(tài) Web 應(yīng)用集成

與 Spring集成

Shiro 的組件都是 JavaBean/POJO 式的組件,所以非常容易使用 Spring 進(jìn)行組件管理,可以非常方便的從 ini 配置遷移到 Spring 進(jìn)行管理,且支持 JavaSE 應(yīng)用及 Web 應(yīng)用的集成。

在示例之前,需要導(dǎo)入 shiro-spring 及 spring-context 依賴,具體請參考 pom.xml。
spring-beans.xml 配置文件提供了基礎(chǔ)組件如 DataSource、DAO、Service 組件的配置。

JavaSE 應(yīng)用

spring-shiro.xml 提供了普通 JavaSE 獨立應(yīng)用的 Spring 配置:

<!-- 緩存管理器 使用Ehcache實現(xiàn) -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
</bean>
<!-- 憑證匹配器 -->
<bean id="credentialsMatcher" class="
com.github.zhangkaitao.shiro.chapter12.credentials.RetryLimitHashedCredentialsMatcher">
    <constructor-arg ref="cacheManager"/>
    <property name="hashAlgorithmName" value="md5"/>
    <property name="hashIterations" value="2"/>
    <property name="storedCredentialsHexEncoded" value="true"/>
</bean>
<!-- Realm實現(xiàn) -->
<bean id="userRealm" class="com.github.zhangkaitao.shiro.chapter12.realm.UserRealm">
    <property name="userService" ref="userService"/>
    <property name="credentialsMatcher" ref="credentialsMatcher"/>
    <property name="cachingEnabled" value="true"/>
    <property name="authenticationCachingEnabled" value="true"/>
    <property name="authenticationCacheName" value="authenticationCache"/>
    <property name="authorizationCachingEnabled" value="true"/>
    <property name="authorizationCacheName" value="authorizationCache"/>
</bean>
<!-- 會話ID生成器 -->
<bean id="sessionIdGenerator" 
class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>
<!-- 會話DAO -->
<bean id="sessionDAO" 
class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
    <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>
    <property name="sessionIdGenerator" ref="sessionIdGenerator"/>
</bean>
<!-- 會話驗證調(diào)度器 -->
<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.session.mgt.DefaultSessionManager">
    <property name="globalSessionTimeout" value="1800000"/>
    <property name="deleteInvalidSessions" value="true"/>
    <property name="sessionValidationSchedulerEnabled" value="true"/>
   <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
    <property name="sessionDAO" ref="sessionDAO"/>
</bean>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.mgt.DefaultSecurityManager">
    <property name="realms">
        <list><ref bean="userRealm"/></list>
    </property>
    <property name="sessionManager" ref="sessionManager"/>
    <property name="cacheManager" ref="cacheManager"/>
</bean>
<!-- 相當(dāng)于調(diào)用SecurityUtils.setSecurityManager(securityManager) -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" 
value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
    <property name="arguments" ref="securityManager"/>
</bean>
<!-- Shiro生命周期處理器-->
<bean id="lifecycleBeanPostProcessor" 
class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

可以看出,只要把之前的 ini 配置翻譯為此處的 spring xml 配置方式即可,無須多解釋。 LifecycleBeanPostProcessor 用于在實現(xiàn)了 Initializable 接口的 Shiro bean 初始化時調(diào)用 Initializable 接口回調(diào),在實現(xiàn)了 Destroyable 接口的 Shiro bean 銷毀時調(diào)用 Destroyable 接口回調(diào)。如 UserRealm 就實現(xiàn)了 Initializable,而 DefaultSecurityManager 實現(xiàn)了 Destroyable。具體可以查看它們的繼承關(guān)系。

測試用例請參考 com.github.zhangkaitao.shiro.chapter12.ShiroTest。

Web 應(yīng)用

Web 應(yīng)用和普通 JavaSE 應(yīng)用的某些配置是類似的,此處只提供一些不一樣的配置,詳細(xì)配置可以參考 spring-shiro-web.xml。

<!-- 會話Cookie模板 -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
    <constructor-arg value="sid"/>
    <property name="httpOnly" value="true"/>
    <property name="maxAge" value="180000"/>
</bean>
<!-- 會話管理器 -->
<bean id="sessionManager" 
class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    <property name="globalSessionTimeout" value="1800000"/>
    <property name="deleteInvalidSessions" value="true"/>
    <property name="sessionValidationSchedulerEnabled" value="true"/>
    <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
    <property name="sessionDAO" ref="sessionDAO"/>
    <property name="sessionIdCookieEnabled" value="true"/>
    <property name="sessionIdCookie" ref="sessionIdCookie"/>
</bean>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm"/>
    <property name="sessionManager" ref="sessionManager"/>
    <property name="cacheManager" ref="cacheManager"/>
</bean>&nbsp;
  1. sessionIdCookie 是用于生產(chǎn) Session ID Cookie 的模板;
  2. 會話管理器使用用于 web 環(huán)境的 DefaultWebSessionManager;
  3. 安全管理器使用用于 web 環(huán)境的 DefaultWebSecurityManager。
<!-- 基于Form表單的身份驗證過濾器 -->
<bean id="formAuthenticationFilter" 
class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
    <property name="usernameParam" value="username"/>
    <property name="passwordParam" value="password"/>
    <property name="loginUrl" value="/login.jsp"/>
</bean>
<!-- Shiro的Web過濾器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <property name="loginUrl" value="/login.jsp"/>
    <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
    <property name="filters">
        <util:map>
            <entry key="authc" value-ref="formAuthenticationFilter"/>
        </util:map>
    </property>
    <property name="filterChainDefinitions">
        <value>
            /index.jsp = anon
            /unauthorized.jsp = anon
            /login.jsp = authc
            /logout = logout
            /** = user
        </value>
    </property>
</bean>&nbsp;
  1. formAuthenticationFilter 為基于 Form 表單的身份驗證過濾器;此處可以再添加自己的 Filter bean 定義;
  2. shiroFilter:此處使用 ShiroFilterFactoryBean 來創(chuàng)建 ShiroFilter 過濾器;filters 屬性用于定義自己的過濾器,即 ini 配置中的 [filters] 部分;filterChainDefinitions 用于聲明 url 和 filter 的關(guān)系,即 ini 配置中的 [urls] 部分。

接著需要在 web.xml 中進(jìn)行如下配置:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:spring-beans.xml,
        classpath:spring-shiro-web.xml
    </param-value>
</context-param>
<listener>
   <listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>&nbsp;

通過 ContextLoaderListener 加載 contextConfigLocation 指定的 Spring 配置文件。

<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>&nbsp;

DelegatingFilterProxy 會自動到 Spring 容器中查找名字為 shiroFilter 的 bean 并把 filter 請求交給它處理。

其他配置請參考源代碼。

Shiro 權(quán)限注解

Shiro 提供了相應(yīng)的注解用于權(quán)限控制,如果使用這些注解就需要使用 AOP 的功能來進(jìn)行判斷,如 Spring AOP;Shiro 提供了 Spring AOP 集成用于權(quán)限注解的解析和驗證。

為了測試,此處使用了 Spring MVC 來測試 Shiro 注解,當(dāng)然 Shiro 注解不僅僅可以在 web 環(huán)境使用,在獨立的 JavaSE 中也是可以用的,此處只是以 web 為例了。

在 spring-mvc.xml 配置文件添加 Shiro Spring AOP 權(quán)限注解的支持:

<aop:config proxy-target-class="true"></aop:config>
<bean class="
org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
    <property name="securityManager" ref="securityManager"/>
</bean>&nbsp;

如上配置用于開啟 Shiro Spring AOP 權(quán)限注解的支持;<aop:config proxy-target-class="true"> 表示代理類。

接著就可以在相應(yīng)的控制器(AnnotationController)中使用如下方式進(jìn)行注解:

@RequiresRoles("admin")
@RequestMapping("/hello2")
public String hello2() {
    return "success";
}&nbsp;

訪問 hello2 方法的前提是當(dāng)前用戶有 admin 角色。

當(dāng)驗證失敗,其會拋出 UnauthorizedException 異常,此時可以使用 Spring 的 ExceptionHandler(DefaultExceptionHandler)來進(jìn)行攔截處理:

@ExceptionHandler({UnauthorizedException.class})
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public ModelAndView processUnauthenticatedException(NativeWebRequest request, UnauthorizedException e) {
    ModelAndView mv = new ModelAndView();
    mv.addObject("exception", e);
    mv.setViewName("unauthorized");
    return mv;
}&nbsp;

如果集成 Struts2,需要注意《Shiro+Struts2+Spring3 加上 @RequiresPermissions 后 @Autowired 失效》問題:
http://jinnianshilongnian.iteye.com/blog/1850425

權(quán)限注解

@RequiresAuthentication

表示當(dāng)前 Subject 已經(jīng)通過 login 進(jìn)行了身份驗證;即 Subject.isAuthenticated() 返回 true。

@RequiresUser

表示當(dāng)前 Subject 已經(jīng)身份驗證或者通過記住我登錄的。

@RequiresGuest

表示當(dāng)前 Subject 沒有身份驗證或通過記住我登錄過,即是游客身份。

@RequiresRoles(value={“admin”, “user”}, logical= Logical.AND)

表示當(dāng)前 Subject 需要角色 admin 和 user。

@RequiresPermissions (value={“user:a”, “user:b”}, logical= Logical.OR)

表示當(dāng)前 Subject 需要權(quán)限 user:a 或 user:b。

上一篇:在線會話管理下一篇:授權(quán)