Redis+Shiro+Spring-data-redis,共享Session

环境:centos7,Java1.8+,一个Nginx,两个Tomcat,一个Redis。

关于共享session的问题大家都应该知道了,传统的部署项目,两个相同的项目部署到不同的服务器上,Nginx负载均衡后会导致用户在A上登陆了,经过负载均衡后,在B上要重新登录,因为A上有相关session信息,而B没有。这种情况也称为“有状态”服务。而“无状态”服务则是:在一个公共的地方存储session,每次访问都会统一到这个地方来拿。

Redis+Shiro+Spring-data-redis,共享Session_第1张图片

为了方便我只用了一台linux虚拟机。

如果你使用了Shiro权限管理呢,他的好处之一就是会话管理,由Shiro管理Session,而不是Tomcat。听说都在用Spring-Session,实际上它和shiro一样,请看web.xml里面的配置



    
    <filter>
        <filter-name>shiroFilterfilter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
        <init-param>
            <param-name>targetFilterLifecycleparam-name>
            <param-value>trueparam-value>
        init-param>
    filter>

    <filter-mapping>
        <filter-name>shiroFilterfilter-name>
        <url-pattern>/*url-pattern>
        <dispatcher>REQUESTdispatcher>
        <dispatcher>FORWARDdispatcher>
        <dispatcher>INCLUDEdispatcher>
        <dispatcher>ERRORdispatcher>
    filter-mapping>

不难看出,这两个都是基于:org.springframework.web.filter.DelegatingFilterProxy

下面开始正题。

使用Shiro需要继承AbstractSessionDAO

package com.internetsaying.auth.session;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.internetsaying.auth.redis.RedisManager;

@Component
public class MySessionDao extends AbstractSessionDAO {

    @Autowired
    private RedisManager redisManager;
    
    @Override
    public void delete(Session session) {
        if(session == null || session.getId() == null){
            System.out.println("Session is null");
            return;
        }
        redisManager.hdelete(session.getId().toString());
    }

    @Override
    public Collection getActiveSessions() {
        List list = redisManager.hmget();
        return list;
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        if(session == null || session.getId() == null){
            System.out.println("Session is null");
            return;
        }
        Serializable sessionId = session.getId();
        redisManager.hadd(sessionId.toString(), session);
    }

    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = generateSessionId(session);
        assignSessionId(session, sessionId);
        //添加进redis
        redisManager.hadd(sessionId.toString(), session);
        
        return sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        return redisManager.hget(sessionId.toString());
    }


    
}

下面是RedisManager的代码

package com.internetsaying.auth.redis;

import java.util.ArrayList;
import java.util.List;

import org.apache.shiro.session.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@Component
public class RedisManager {

    @Autowired
    private RedisTemplate redisTemplate;
    
    private static final String KEY = "shareSessionMap";
    
    public void hadd(String sessionId, byte[] bytes){
        redisTemplate.boundHashOps(KEY).put(sessionId, bytes);
    }
    public void hadd(String sessionId, Session session){
        redisTemplate.boundHashOps(KEY).put(sessionId, session);
    }
    
    public void hdelete(String sessionId){
        redisTemplate.boundHashOps(KEY).delete(sessionId);
    }
    
    public Session hget(String sessionId){
        return (Session) redisTemplate.boundHashOps(KEY).get(sessionId);
    }
    
    public List hmget(){
        List list = new ArrayList<>();
        
        List values = redisTemplate.boundHashOps(KEY).values();
        for (Object object : values) {
            list.add((Session) object);
        }
        return list;
    }
} 
    
   

配置文件:shiro和redis部分(只是与共享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:context="http://www.springframework.org/schema/context"
    xmlns:core="http://activemq.apache.org/schema/core"
    xmlns:redis="http://www.springframework.org/schema/redis"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core
        http://www.springframework.org/schema/redis http://www.springframework.org/schema/redis/spring-redis-1.0.xsd">


    
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        
        <property name="sessionManager" ref="sessionManager">property>
    bean>
    
    <bean id="redisManager" class="com.internetsaying.auth.redis.RedisManager">bean>
    
    <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator">bean>
    
    <bean id="sessionDAO" class="com.internetsaying.auth.session.MySessionDao">
        <property name="sessionIdGenerator" ref="sessionIdGenerator">property>
    bean>
    
    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <property name="globalSessionTimeout" value="1800000">property>
        <property name="deleteInvalidSessions" value="true">property>
        <property name="sessionDAO" ref="sessionDAO">property>
        
        <property name="sessionIdCookie" ref="sharesession" />
    bean>
    
    <bean id="sharesession" class="org.apache.shiro.web.servlet.SimpleCookie">
        
        <constructor-arg name="name" value="SHAREJSESSIONID" />
        
        <property name="path" value="/" />
        <property name="httpOnly" value="true"/>
    bean>
    
    
    <context:property-placeholder location="classpath:redis.properties"/>
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="${redis.maxIdle}">property>
        <property name="maxTotal" value="${redis.maxTotal}">property>
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}">property>
        <property name="testOnBorrow" value="${redis.testOnBorrow}">property>
    bean>

    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="usePool" value="${redis.pooled}">property>
        <property name="hostName" value="${redis.host}">property>
        <property name="port" value="${redis.port}">property>
        <property name="poolConfig" ref="jedisPoolConfig">property>
    bean>
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory">property>
        <property name="keySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer">bean>
        property>
        
        <property name="valueSerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer">bean>
        property>
        <property name="hashKeySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer">bean>
        property>
    bean>
    
beans>

配置文件:redis.properties

#Redis settings

redis.host=127.0.0.1
redis.port=6379
#redis.pass=
redis.maxIdle=30
redis.maxTotal=100
redis.maxWaitMillis=1000
redis.testOnBorrow=true
redis.pooled=true

执行流程

Redis+Shiro+Spring-data-redis,共享Session_第2张图片

说明:由于做的是分布式项目,不便贴上全部代码,如遇问题可联系我:3110320051.

我有个完整的小栗子

部署

关于Nginx做负载均衡可参考我上一篇文章。

这里将项目打包后,分别上传到两个Tomcat,启动。当访问时。【页面过于简单,仅供测试】

Redis+Shiro+Spring-data-redis,共享Session_第3张图片

点击登录既完成Shiro的认证授权,跳转到可访问页面。

Redis+Shiro+Spring-data-redis,共享Session_第4张图片

刷新

Redis+Shiro+Spring-data-redis,共享Session_第5张图片

 

注意cookie的Value

现在我们看一下redis存储的:

[root@localhost local]# ./bin/redis-cli 
127.0.0.1:6379> keys *
1) "shareSessionMap"
127.0.0.1:6379> HKEYS shareSessionMap
1) "a511c5c4-9f61-4c24-aad2-b551f8053ebf"

所以:每次服务器都是去redis里面去拿的session,登录A后,切换到B不需要重新登录。

 

转载于:https://www.cnblogs.com/LUA123/p/7728319.html

你可能感兴趣的:(Redis+Shiro+Spring-data-redis,共享Session)