前段时间研究了一下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。