前段時間研究了一下shiro,因爲看不懂英文所以學習過程頗爲曲折,後來整合shiro想寫一個sso結果這段時間又寫不下去了只好來寫寫博客了。
最初學shiro是在百度搜教程,說實話那些教程除了開濤寫的其它人寫的確實不怎麼樣,而且開濤的教程也不是特別詳細的那種,所以我在這給大家寫一個整合後的完整教程。
shiro的設計思想我在這就不多說了,實話我說只明白一小半甚至一小半都沒有,要說思想開濤的博客的前幾章講的很好,所以我在這不重複了這裏我只講些實用的東西能讓你快速上手的。
先上個Spring mvc的配置文件,具體都是什麼配置請自行百度這個教程太多了我在這就不講了。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context"
default-lazy-init="false">
<description>Spring公共配置 </description>
<!-- 定義受環境影響易變的變量 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<!-- 標準配置 -->
<value>classpath*:/application.properties</value>
<value>classpath*:/config/shiro.properties</value>
</list>
</property>
</bean>
<!-- 激活 @Required @Autowired,JSR 250's @PostConstruct, @PreDestroy and @Resource 等標註 -->
<context:annotation-config />
<!-- 使用annotation 自動註冊bean,並保證@Required,@Autowired的屬性被注入 -->
<context:component-scan base-package="com.sso" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 數據源配置,使用應用內的DBCP數據庫連接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- Connection Info -->
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- Connection Pooling Info -->
<property name="initialSize" value="${dbcp.initialSize}" />
<property name="maxActive" value="${dbcp.maxActive}" />
<property name="maxIdle" value="${dbcp.maxIdle}" />
<property name="defaultAutoCommit" value="false" />
</bean>
<!-- 數據源配置,使用應用服務器的數據庫連接池 -->
<!--<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/ExampleDB" />-->
<!-- Mybatis配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="typeAliasesPackage" value= "com.sso.entity,;" />
</bean>
<!-- scan for mappers and let them be autowired -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value= "com.sso.dao,;" />
</bean>
<!-- Transaction manager for a single JDBC DataSource -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 使用annotation定義事務 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<!-- SpringContext Holder -->
<bean id="springContextHolder" class="com.sso.sys.SpringContextHolder" lazy-init="false"/>
</beans>
下面這個是重點shiro的spring配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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"
default-lazy-init="false">
<!-- shiroDbRealm -->
<bean id="shiroDbRealm" class="com.sso.shiro.RealmManager"></bean>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="shiroDbRealm" />
<property name="sessionManager" ref="sessionManager" />
<!-- 緩存管理器 -->
<property name="cacheManager" ref="shiroCacheManager" />
</bean>
<!-- apache默認的session管理定時器 -->
<bean name="sessionValidationScheduler " class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler">
</bean>
<bean id="sessionManager" class="com.sso.shiro.MySessionManager">
<!-- 超時時間 -->
<property name="globalSessionTimeout" value="${sessionTimeout}" /><!-- 這是shrio管理session的超時時間 -->
<property name="sessionDAO" ref="shiroSessionDao" /><!-- 這裏對session的CURD操作 -->
<property name="sessionIdCookie" ref="sharesession" /><!-- shiro自己的cookie管理器 -->
<!-- 啓動shiro自己的session檢查定時器 定時檢查失效的session 默認半小時執行一次-->
<property name="sessionValidationSchedulerEnabled" value="true" />
</bean>
<bean id="sharesession" class="org.apache.shiro.web.servlet.SimpleCookie">
<property name="name" value="${domain}" />
</bean>
<bean id="shiroSessionDao" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO" />
<!-- 單機session -->
<bean id="shiroCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />
<!-- 自定義的權限加載機制 -->
<bean id="chainDefinitionSectionMetaSource" class="com.sso.shiro.DefaultChainDefinitionsFactoryBean" />
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/gotoLoginView" />
<property name="successUrl" value="/viewAllContacts.do" />
<property name="unauthorizedUrl" value="/meiquanxian" />
<property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource" />
<property name="filters">
<map>
<entry key="perms">
<bean class="com.sso.shiro.MyPermsAuthorizationFilter"/>
</entry>
<entry key="authc">
<bean class="com.sso.shiro.MyFormAuthenticationFilter"/>
</entry>
<entry key="ws">
<bean class="com.sso.shiro.WebServiceAuthorizationFilter"/>
</entry>
</map>
</property>
</bean>
<!-- 起效權限註解,這個很少在web項目中用到,一般是控制url的訪問,不是在controller中聲明權限註解 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
</beans>
從上到下依次給大家講解。
1、shiroDbRealm:這是一個自定義的realm,realm的作用我的理解就是用來給用戶登陸和設置權限的。具體講解請看第二章。
2、securityManager:安全管理器,從它的注入屬性來看,他管理着用戶的realm、session、cache,我的理解是可以將他看作是一箇中心,所有的操作都要經過它的調度。
3、sessionValidationScheduler:他是shiro自己的一個session管理器,從源碼可以看出它其實就是一個線程,這個東西不需要手動注入,這裏列出來是因爲我覺得默認30分鐘一次的刷新頻率太低了,當初想通過這種方式來改掉他的默認時間,大家從我只寫了一行代碼可以看出結果當然是失敗的。
4、sessionManager:這是對session所有操作的一個管理類。
5、sharsession:用來設置當前會話的cookie設置,屬性包括cookie所的屬性。
6、shiroCacheMnanager:chche管理器,這裏面是一個單機版的管理器,如果是集羣據說要重寫sessionDAO這個組件,具體的沒有研究過,過後再研究一下。
7、chainDefinitionSectionMetaSource:這個是我自己寫資源加載器,大家都知道shiro的標準配置方式是在xml裏面配置資源地址而在xml裏面配置地址會有很多的不便,經過研究最終寫出了通過項目啓動時訪問數據庫來加載地址的方式。具體的實現方式在後面會講到。
8、shiroFilter:這是shiro攔截器的入口位置,用來初始化所有需要的組件及參數。
9、lifecycleBeanPostProcessor:說實話不知道這是幹嘛的,看註釋意思是使用註解來控制權限。
下面是web.xml的一個設置:
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:web="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<display-name>member</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/applicationContext*.xml</param-value>
</context-param>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<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>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
前半部分是對編碼的一個設置,中間部分是shiro的設置,在這裏要說一下shiro攔截器的加載方法與普通攔截器不一樣具體原理沒明白但有一點filter-name必須要與xml裏面定義的bean id一樣否則會報錯。在shiro的後面就是spring自己的配置了跟正常的一樣沒什麼好說的。
在這要說一句,shiro裏面接管了session默認的應該是30分鐘,如果在這裏設置的話應該就不起作用了需要在shiro的配置項裏面去設置globalSessionTimeOut。