Spring Session+Redis零侵入实现单点登录

Spring Session 实现单点登录

此种方式相对于上节所说使用原生(Jedis+Jackson+Cookie+Filter)的方式实现起来更加简便,同时对业务代码的侵入性也十分之小,其原理与原生方式类似,并通过对HttpServletRequest和HttpServletResponse的包装来实现cookie的读写,序列化采用JDK原生的方式,故用户对象(User)需要实现Serializable接口, 
在说明具体如何配置之前,有必要说一下,在本项目中分布式Session是如何演进的。

在最初,我们的User模块是这样的,用户登录信息存入Tomcat容器自带的Session中,这也是通用的做法,也很简单,适合单服务器部署:

v1.0 版本

/**
     *用户登录
     */
    @RequestMapping(value = "login.do",method = RequestMethod.GET)
    @ResponseBody
    public ServerResponse<User> login(String username, String password, HttpSession session){

        ServerResponse<User> response = iUserService.login(username, password);
        if (response.isSuccess()) {
            session.setAttribute(Const.CURRENT_USER,response.getData());
        }
        return response;
    }

v2.0版本

此时随着系统演进,服务器升级为集群模式,或多子系统等架构,Tomcat自带的Session管理是基于Http协议的无状态对象,故我们将Session集中管理起来,放入第三方,比如Redis缓存中,所有服务节点重Session会话中心进行登录认证。单点登录的实现方式为 Session存入Redis,token写入Cookie,用户带着Cookie中的token来进行认证,此时,我们使用原生方式实现,代码会是这样:

/**
     *用户登录
     */
    @RequestMapping(value = "login.do",method = RequestMethod.GET)
    @ResponseBody
    public ServerResponse<User> login(String username, String password, HttpSession session,HttpServletResponse httpServletResponse){

        ServerResponse<User> response = iUserService.login(username, password);
        if (response.isSuccess()) {
//            session.setAttribute(Const.CURRENT_USER,response.getData());
            //写入cookie
            CookieUtil.writeLoginToken(httpServletResponse,session.getId());
            //将登录用户信息存入redis,有效时间为30分钟
            RedisPoolUtil.setEx(session.getId(), JsonUtil.obj2string(response.getData()), Const.RedisCacheExTime.REDIS_SESSION_EXTIME);
        }
        return response;
    }

v3.0 从上面的实现方式也看出来了,在login方法中加入了读写cookie和redis的逻辑,在我们的业务中通常会有很多地方需要对用户信息进行认证,故这样的代码对业务代码的侵入性很大,很多地方都要写这些业务无关代码。

这时我们使用Spring Session提供的方式来实现分布式的Session管理,其原理是与V2.0一样的,不过Spring对其进行的封装和优化。集成Spring Session之后,我们的代码于是就又变回了V1.0的写法:

这样的好处就是,在系统演进的过程中,我们不需要改变原有代码,迭代的复杂度也大大降低。

 @RequestMapping(value = "login.do",method = RequestMethod.GET)
    @ResponseBody
    public ServerResponse<User> login(String username, String password, HttpSession session){

        ServerResponse<User> response = iUserService.login(username, password);
        if (response.isSuccess()) {
            session.setAttribute(Const.CURRENT_USER,response.getData());
        }
        return response;
    }

Spring Session配置

1 引入依赖,并将Spring版本改成4.0.3

<dependency>
      <groupId>org.springframework.session</groupId>
      <artifactId>spring-session-data-redis</artifactId>
      <version>1.3.1.RELEASE</version>
</dependency>

2 在web.xml中加入过滤器DelegatingFilterProxy

<!-- spring session 的过滤器-->
    <filter>
        <filter-name>springSessionRepositoryFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSessionRepositoryFilter</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping>

3 在applicationContext.xml中<import resource="applicationContext-spring-session.xml"/>
   并在applicationContext-spring-session的配置文件中添加配置

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        <property name="maxInactiveIntervalInSeconds" value="1800" />
    </bean>

    <bean id="defaultCookieSerializer" class="org.springframework.session.web.http.DefaultCookieSerializer">
        <property name="domainName" value=".happymmall.com" />
        <property name="useHttpOnlyCookie" value="true" />
        <property name="cookiePath" value="/" />
        <property name="cookieMaxAge" value="31536000" />
    </bean>

    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal" value="20"/>
    </bean>

    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="127.0.0.1" />
        <property name="port" value="6379" />
        <property name="poolConfig" ref="jedisPoolConfig" />
    </bean>

</beans>

5 小结

通过Redis+Spring Session实现的单点登录系统对业务代码侵入性非常小,在单服务器时使用session存取用户信息,在集群模式时代码无需改变,只要引入Spring Session相关配置即可。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值