Shiro + Redis集成思路
首先,确保Spring配置完毕了。
集成Shiro
1、在pom.xml中追加依赖
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency>
2、追加spring-shiro.xml
<?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"> <bean id="myShiroRealm" class="io.spldeolin.bestpractice.shiro.component.Realm"> <property name="cacheManager" ref="cacheManager" /> </bean> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="myShiroRealm" /> <property name="cacheManager" ref="cacheManager" /> <property name="sessionManager" ref="sessionManager" /> </bean> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="sessionIdUrlRewritingEnabled" value="false" /> <property name="globalSessionTimeout" value="3600000" /> </bean> <!-- 自带的、缓存在内存的、不支持集群的缓存管理器 --> <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" /> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <!-- loginUrl 未认证时,访问需要认证资源时的重定向url --> <property name="loginUrl" value="/" /> <!-- successUrl 登录成功后的重定向url --> <property name="successUrl" value="/loginsuccess.jhtml" /> <!-- unauthorizedUrl 访问无权限资源时的重定向url --> <property name="unauthorizedUrl" value="/error.jhtml" /> <property name="filterChainDefinitions"> <value> /** = anon </value> </property> </bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true" /> </bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean> </beans>
有三个主要的组件,Realm、SecurityManager、ShiroFilter。
Realm代表用来取得用于验证和授权的数据的策略。
SecurityManager持有Realm对象、CacheManager对象、SessionManager对象。后两者代表缓存策略和会话管理策略,演示代码采取的是Shiro默认策略
ShiroFilter代表过滤器,为web.xml中配置的过滤器提供支持。
3、在web.xml中追加ShiroFilter
<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>
4、实现spring-shiro.xml涉及到的自定义类,示例代码中,只需要实现Realm
集成Redis
5、在pom.xml中追加依赖
<dependency> <groupId>org.crazycake</groupId> <artifactId>shiro-redis</artifactId> <version>2.4.2.1-RELEASE</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.7.2</version> </dependency>
6、追加spring-redis.xml
<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"> <bean id="redisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="${redis.pool.maxActive}" /> <property name="maxIdle" value="${redis.pool.maxIdle}" /> <property name="maxWaitMillis" value="${redis.pool.maxWait}" /> <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" /> </bean> <bean id="jedisPool" class="redis.clients.jedis.JedisPool" destroy-method="destroy"> <constructor-arg ref="redisPoolConfig" /> <constructor-arg value="${redis.host}" /> <constructor-arg type="int" value="${redis.port}" /> <constructor-arg type="int" value="${redis.timeout}" /> <constructor-arg type="java.lang.String" value="${redis.password}" /> <constructor-arg type="int" value="${redis.dbindex}" /> </bean> <bean id="redisClient" class="io.spldeolin.logindemo.shiro.component.RedisClient4Shiro"> <constructor-arg name="jedisPool" ref="jedisPool" /> <property name="expire" value="${redis.default.expire}" /> </bean> </beans>
实际上,还需要追加redis.properties,这里省略
7、修改spring-shiro.xml中SecurityManager的SessionManager(会话管理策略)
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="realm" /> <property name="cacheManager" ref="cacheManager" /> <!-- 【securityManager的sessionManager相关】 --> <property name="sessionManager"> <!-- Shiro自带的session管理方式——DefaultWebSessionManager和MemorySessionDAO --> <!-- <bean class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="sessionIdUrlRewritingEnabled" value="false" /> <property name="globalSessionTimeout" value="3600000" /> </bean> --> <!-- Redis的session管理方式——DefaultWebSessionManager和RedisSessionDAO --> <bean class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="globalSessionTimeout" value="1800000" /> <property name="sessionValidationInterval" value="1800000" /> <property name="sessionDAO"> <bean class="org.crazycake.shiro.RedisSessionDAO"> <property name="redisManager" ref="redisClient" /> </bean> </property> <property name="sessionIdCookie"> <bean class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg name="name" value="custom.session" /> <property name="path" value="/" /> </bean> </property> <property name="sessionIdUrlRewritingEnabled" value="false" /> </bean> </property> <!-- 记住我的失效时间,单位是秒 --> <property name="rememberMeManager.cookie.maxAge" value="100000"></property> </bean>
这里的关键是org.crazycake.shiro.RedisSessionDAO
8、修改spring-shiro.xml中SecurityManager的cacheManager(缓存策略)
<!-- Shiro自带的缓存管理 --> <!-- <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" /> --> <!-- Redis的缓存管理 --> <bean id="cacheManager" class="org.crazycake.shiro.RedisCacheManager"> <property name="keyPrefix" value="shiro_redis_session:" /> <property name="redisManager" ref="redisClient" /> </bean>
可以看到spring-redis.xml与新的spring-shiro.xml的联系点在redisClient这个bean。
9、实现RedisClient4Shiro类
public class RedisClient4Shiro extends RedisManager { private JedisPool jedisPool = null; public RedisClient4Shiro(JedisPool jedisPool) { this.jedisPool = jedisPool; } @Override public void init() { super.init(); } @Override public byte[] get(byte[] key) { Jedis jedis = jedisPool.getResource(); byte[] value; try { value = jedis.get(key); } catch (Exception e) { throw new RuntimeException("redis operation error:", e); } finally { jedis.close(); } return value; } @Override public byte[] set(byte[] key, byte[] value) { Jedis jedis = jedisPool.getResource(); try { jedis.set(key, value); Integer expire = getExpire(); if (expire != 0) { jedis.expire(key, expire); } } catch (Exception e) { throw new RuntimeException("redis operation error:", e); } finally { jedis.close(); } return value; } @Override public byte[] set(byte[] key, byte[] value, int expire) { Jedis jedis = jedisPool.getResource(); try { jedis.set(key, value); if (expire != 0) { jedis.expire(key, expire); } } catch (Exception e) { throw new RuntimeException("redis operation error:", e); } finally { jedis.close(); } return value; } @Override public void del(byte[] key) { Jedis jedis = jedisPool.getResource(); try { jedis.del(key); } catch (Exception e) { throw new RuntimeException("redis operation error:", e); } finally { jedis.close(); } } @Override public void flushDB() { Jedis jedis = jedisPool.getResource(); try { jedis.flushDB(); } catch (Exception e) { throw new RuntimeException("redis operation error:", e); } finally { jedis.close(); } } @Override public Long dbSize() { Long dbSize = Long.valueOf(0L); Jedis jedis = jedisPool.getResource(); try { dbSize = jedis.dbSize(); } catch (Exception e) { throw new RuntimeException("redis operation error:", e); } finally { jedis.close(); } return dbSize; } @Override public Set<byte[]> keys(String pattern) { Set<byte[]> keys = null; Jedis jedis = jedisPool.getResource(); try { keys = jedis.keys(pattern.getBytes()); } catch (Exception e) { throw new RuntimeException("redis operation error:", e); } finally { jedis.close(); } return keys; } }
详细:Github