基于shiro+redis缓存的session共享方案

来源:互联网 发布:在手机上编程的软件 编辑:程序博客网 时间:2024/06/05 02:37

基于shiro+redis缓存的session共享方案

 

当一个使用shiro开发的项目被定位为单机部署,不需要集群部署时,我们可以不考虑shiro redis集群;然而很多大型项目是需要集群部署的,以应对高并发访问量。

由 redis负责 session 数据的存储和授权信息cache共享,而我们自己实现的 session manager 将负责 session 生命周期的管理。结构示例如下图

 

特征:

  • 可以使用redis管理shiro session
  • 解决集群中session同步的问题
  • 解决集群中缓存应用的问题
  • 多个不同子域名很容易实现统一登陆
  •  

此方案的不足之处:

  • 不同的域名(非子域名)做session共享,只能通过单点登录。
  • redis单点故障,可能需要集群式部署

 

·       项目配置几处关键点: 

·       web.xml主要配置示例

·       <!-- addshiro filter -->

·       <filter>

·           <!--需要在(parent) context中声明id为shiroFilter的bean-->

·           <filter-name>shiroFilter</filter-name>

·           <!--DelegatingFilterProxy,该类其实并不能说是一个过滤器,它的原型是FilterToBeanProxy,即将Filter作为spring的bean,由spring来管理-->

·           <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>

·           <dispatcher>REQUEST</dispatcher>

·           <dispatcher>FORWARD</dispatcher>

·           <dispatcher>INCLUDE</dispatcher>

·           <dispatcher>ERROR</dispatcher>

·       </filter-mapping>

·       <!-- addshiro filter end -->

 

spring-shiro.xml   主要配置示例

<!-- shiro的Web主过滤器,beanId 和web.xml中配置的filter name需要保持一致 -->

<beanid="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

    <!--安全管理器 -->

    <propertyname="securityManager" ref="securityManager"/>

    <!--默认的登陆访问url -->

    <propertyname="loginUrl" value="/login"/>

    <!--登陆成功后跳转的url -->

    <propertyname="successUrl" value="/index"/>

    <!--没有权限跳转的url -->

    <propertyname="unauthorizedUrl" value="/unauthorized"/>

    <!--<propertyname="filters">-->

    <!--<util:map>-->

    <!--<entrykey="authc" value-ref="formAuthenticationFilter"/>-->

    <!--</util:map>-->

    <!--</property>-->

    <!--访问地址的过滤规则,从上至下的优先级,如果有匹配的规则,就会返回,不会再进行匹配 -->

    <propertyname="filterChainDefinitions">

        <value>

            /js/**= anon

            /index.htm*=anon

            /unauthorized.jsp*=anon

            /login.jsp*= anon

            /login.do = authc

            /logout.do = authc

            /**= authc

        </value>

    </property>

</bean>

 

<!-- 权限管理器 -->

<beanid="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

 

    <!--Single realm app.  If you have multiple realms, use the 'realms' property instead. -->

 

    <!--基于redis登录校验的实现 -->

    <propertyname="realm" ref="redisRealm"/>

 

    <!--session 管理器 -->

    <propertyname="sessionManager" ref="sessionManager"/>

 

    <!--缓存管理器 -->

    <propertyname="cacheManager" ref="cacheManager"/>

 

    <!--By default the servletcontainer sessions will be used.  Uncomment this line

         touse shiro's native sessions (seethe JavaDoc for more): -->

    <!--<property name="sessionMode" value="native"/> -->

</bean>

 

<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->

<beanid="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

 

<!--开启Shiro的注解-->

<beanclass="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"

      depends-on="lifecycleBeanPostProcessor"/>

<beanclass="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">

    <propertyname="securityManager" ref="securityManager"/>

</bean>

 

<!--redisSessionDAO -->

<beanid="redisSessionDAO" class="com.xxxx.webkits.shiro.RedisSessionDAO">

    <!--redissession过期时间,单位秒-->

    <propertyname="expire" value="3600"/>

    <!--为了避免项目间session key冲突,需要设置单独的keyPrefix -->

    <!--<propertyname="keyPrefix" value="shiro_redis_session:"/>-->

</bean>

 

<!--session管理器 -->

<beanid="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">

    <propertyname="sessionDAO" ref="redisSessionDAO"/>

    <propertyname="sessionIdCookie" ref="sessionIdCookie"/>

</bean>

 

<!-- cache管理器 -->

<beanid="cacheManager" class="com.xxxxx.webkits.shiro.RedisCacheManager">

    <!--rediscache过期时间,单位秒-->

    <propertyname="expire" value="3600"/>

    <!--为了避免项目间session cache key冲突,需要设置单独的keyPrefix -->

    <!--<propertyname="keyPrefix" value="shiro_redis_cache:"/>-->

</bean>

 

<!-- 会话Cookie模板 -->

<beanid="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">

    <constructor-argvalue="sid"/>

    <propertyname="httpOnly" value="true"/>

    <!--默认关闭浏览器过期,所以下面一行被注释--> 

  <!--<property name="maxAge" value="180000"/>-->

    <propertyname="domain" value="vip.xkeshi.com"/>

</bean>

 

项目中要是自定义一个Realm类,继承AuthorizingRealm抽象类,重载doGetAuthenticationInfo()与doGetAuthorizationInfo() 实现获取用户信息及授权信息查询

 

/**

 *Created by ylc on 2016/2/1.

 */

@Component("redisRealm")

public class RedisRealm extends AuthorizingRealm {

 

    private RedisManager redisManager;

 

    //权限验证-授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用

    @Override

    protected AuthorizationInfodoGetAuthorizationInfo(PrincipalCollection principalCollection) {....}

 

    //登陆验证-认证回调函数,登录时调用

    @Override

    protected AuthenticationInfodoGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {...} 

 

 

另外:

项目中需要配置 redis 连接池~ 否则无法使用

 

项目依赖示例,仅供参考

<!--framework -->

<dependency>

    <groupId>com.xxxxx</groupId>

    <artifactId>xxxx-framework-webkits</artifactId>

    <version>1.0.8-SNAPSHOT</version>

</dependency>

 

<dependency>

    <groupId>com.xxxx</groupId>

    <artifactId>xxxx-framework-core</artifactId>

    <version>1.0.8-SNAPSHOT</version>

</dependency>

<!--framework end -->

 

<!-- shiro-->

<dependency>

    <groupId>org.apache.shiro</groupId>

    <artifactId>shiro-core</artifactId>

    <version>1.2.3</version>

</dependency>

<dependency>

    <groupId>org.apache.shiro</groupId>

    <artifactId>shiro-web</artifactId>

    <version>1.2.3</version>

</dependency>

<dependency>

    <groupId>org.apache.shiro</groupId>

    <artifactId>shiro-spring</artifactId>

    <version>1.2.3</version>

</dependency>

<!-- shiroend -->