• Shiro之保存Session到数据库中-yellowcong


    将Session统一存放到Mysql数据库中进行管理操作,这样我们就可以通过向操作数据库一样,对session进行操作和处理了。实现Session存储到数据库的大致步骤是,1、创建Session表;2、创建操作Session表的Mapper,3、创建继承EnterpriseCacheSessionDAO 的Dao,4、配置管理session的Dao到securityManager中,5、配置ecache配置。

    源码地址

    https://gitee.com/yellowcong/shior-dmeo/tree/master/test

    环境架构

    服务

    版本

    数据库

    Mysql

    缓存

    ehcache

    框架

    Spring+SpringMVC+Mybatis

    项目结构

    这里写图片描述

    添加SessionDao

    数据库表设计

    数据表设计中,我们可以自己在我的基础上,进行字段的扩展

    CREATE TABLE `sys_session` (
      `id` varchar(200) NOT NULL COMMENT 'Sessoin的id',
      `session` varchar(2000) DEFAULT NULL COMMENT 'Session的序列化对象',
      `username` varchar(32) DEFAULT NULL COMMENT '用户名',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这里写图片描述

    SessionMapper.xml

    
    
    
      
        
        
        
      
    
      
      
        
          SELECT LAST_INSERT_ID()
        
        insert into sys_session (id,session)
        values (#{id,jdbcType=VARCHAR},#{session,jdbcType=VARCHAR})
      
    
      
      
        delete from sys_session where id = #{sessionid,jdbcType=VARCHAR}
      
    
      
      
        update sys_session set 
            session = #{session,jdbcType=VARCHAR} 
            
             , username = #{username,jdbcType=VARCHAR} 
            
        where id = #{id,jdbcType=VARCHAR} 
       
    
       
       
    
      
       
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    SessionMapper.java

    package com.yellowcong.shiro.dao;
    
    import java.util.List;
    
    import org.apache.ibatis.annotations.Param;
    
    import com.yellowcong.shiro.model.Session;
    
    /**
     * 创建日期:2017/12/21
    * 创建时间:8:44:22
    * 创建用户:yellowcong
    * 机能概要: */ public interface SessionMapper { /** * 创建日期:2017/12/21
    * 创建时间:8:44:54
    * 创建用户:yellowcong
    * 机能概要:插入session * * @param session */ public int insert(@Param("id") String id,@Param("session") String session); /** * 创建日期:2017/12/21
    * 创建时间:8:48:06
    * 创建用户:yellowcong
    * 机能概要:删除session * * @param session * @return */ public int delete(String sessionid); /** * * 创建日期:2017/12/21
    * 创建时间:8:48:23
    * 创建用户:yellowcong
    * 机能概要:删除session * * @param session * @return */ public int update(@Param("id") String id,@Param("session") String session,@Param("username") String username); /** * 创建日期:2017/12/21
    * 创建时间:8:49:13
    * 创建用户:yellowcong
    * 机能概要:通过sessionid来获取session数据 * * @param sessionid * @return */ public Session load(String sessionid); /** * 创建日期:2017/12/21
    * 创建时间:11:52:02
    * 创建用户:yellowcong
    * 机能概要:根据用户名获取sesssion * @param username * @return */ public List loadByUserName(@Param("username") String username); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    创建SessionDao,管理session

    SessionDao需要继承EnterpriseCacheSessionDAO ,实现里面的抽象方法,同时,自己还添加了一个根据用户名来获取Session对象的方法。这个里面直接操作Session存储到数据库。

    对于插入用户名,需要在update sessiond的地方做处理,不然获取不到用户名

    package com.yellowcong.shiro.dao;
    
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;
    
    import org.apache.shiro.session.Session;
    import org.apache.shiro.session.UnknownSessionException;
    import org.apache.shiro.session.mgt.ValidatingSession;
    import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
    import org.apache.shiro.subject.support.DefaultSubjectContext;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import com.yellowcong.shiro.utils.SerializableUtils;
    
    /**
     * 创建日期:2017/12/21
    * 创建时间:8:31:04
    * 创建用户:yellowcong
    * 机能概要:用于Session的保存 */ public class SessionDao extends EnterpriseCacheSessionDAO { @Autowired private SessionMapper sessionMapper; public void delete(Session session) { //删除session this.sessionMapper.delete(session.getId().toString()); } public void update(Session session) throws UnknownSessionException { //当是ValidatingSession 无效的情况下,直接退出 if(session instanceof ValidatingSession && !((ValidatingSession)session).isValid() ) { return ; } //检索到用户名 String username = String.valueOf(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY)); //序列化Session this.sessionMapper.update(session.getId().toString(), SerializableUtils.serializ(session),username); } @Override protected Serializable doCreate(Session session) { //生成session的id Serializable sessionId = generateSessionId(session); //给Session设定id assignSessionId(session, sessionId); //插入session 到数据库 this.sessionMapper.insert(session.getId().toString(), SerializableUtils.serializ(session)); return sessionId; } /** * 创建日期:2017/12/21
    * 创建时间:13:56:15
    * 创建用户:yellowcong
    * 机能概要:通过名称来获取用户 Session * @param username * @return */ public List loadByUserName(String username) { //获取session的字符串 List dbSessions = this.sessionMapper.loadByUserName(username); //判断是否存在用户的情况 if(dbSessions == null || dbSessions.size() == 0) { return null; } List result = new ArrayList(); for(com.yellowcong.shiro.model.Session session:dbSessions) { //加载session数据 String sessionStr = session.getSession(); //将Session的数据串,转化为对象 result.add(SerializableUtils.deserializ(sessionStr)); } return result; } @Override protected Session doReadSession(Serializable sessionId) { //获取session的字符串 com.yellowcong.shiro.model.Session dbSession = this.sessionMapper.load(sessionId.toString()); if(dbSession == null) { return null; } //加载session数据 String sessionStr = dbSession.getSession(); return SerializableUtils.deserializ(sessionStr); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103

    SerializableUtils

    序列和反序列Session对象,只有将session对象序列化成字符串,才可以存储到Mysql上,不能直接存

    package com.yellowcong.shiro.utils;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.util.Base64;
    
    import org.apache.shiro.session.Session;
    
    /**
     * 创建日期:2017/12/21
    * 创建时间:9:21:25
    * 创建用户:yellowcong
    * 机能概要: */ public class SerializableUtils { /** * 创建日期:2017/12/21
    * 创建时间:9:25:30
    * 创建用户:yellowcong
    * 机能概要:将Session序列化成String类型 * @param session * @return */ public static String serializ(Session session) { try { //ByteArrayOutputStream 用于存储序列化的Session对象 ByteArrayOutputStream bos = new ByteArrayOutputStream(); //将Object对象输出成byte数据 ObjectOutputStream out = new ObjectOutputStream(bos); out.writeObject(session); //将字节码,编码成String类型数据 return Base64.getEncoder().encodeToString(bos.toByteArray()); } catch (Exception e) { throw new RuntimeException("序列化失败"); } } /** * 创建日期:2017/12/21
    * 创建时间:9:26:19
    * 创建用户:yellowcong
    * 机能概要:将一个Session的字符串序列化成字符串,反序列化 * @param sessionStr * @return */ public static Session deserializ(String sessionStr) { try { //读取字节码表 ByteArrayInputStream bis = new ByteArrayInputStream(Base64.getDecoder().decode(sessionStr)); //将字节码反序列化成 对象 ObjectInputStream in = new ObjectInputStream(bis); Session session = (Session) in.readObject(); return session; } catch (Exception e) { throw new RuntimeException("反序列化失败"); } } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    配置spring-shiro.xml配置文件

    注意这个sessionDao 里面配置了activeSessionsCacheName 这个属性,这个在ecache.xml里面必须也配置一个shiro-activeSessionCache节点,用于存激活的session,简单来讲,就是登录的用户。

    
         
    
             
        
             
        
    
    
        
        
    
        
        
            
            
            
            
        
    
                   
        
        
            
            
    
            
    
            
            
            
            
            
            
    
            
            
            
        
    
        
        
            
            
        
    
            
          
            
              
    
                    
            
    
            
            
                
                    
                    
                    
                
            
    
            
           
         
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    下面是完整配置

    其中还有一部分是关于Shiro生命周期的,存储在了Spring-mvc中,因为生命周期配置在spring-shiro.xml中不生效

    
    
        == Shiro Components ==
    
        
         
    
             
        
             
        
    
    
        
        
    
        
        
            
            
            
            
        
    
                   
        
        
            
            
    
            
    
            
            
            
            
            
            
    
            
            
            
        
    
        
        
            
            
        
    
            
          
            
              
    
                    
            
    
            
            
                
                    
                    
                    
                
            
    
            
           
          
    
    
        
        
            
            
            
        
    
        
        
            
                
                
                
            
        
    
        
        
    
            
            
            
                
                    
                    
                    
                    
                
            
        
    
    
        
        
    
            
            
            
                
                    
                    
                    
                    
                
            
        
    
        
          
             
           
             
           
             
           
             
    
           
           
        
    
       
       
    
       
       
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156

    spring-mvc.xml的shiro配置

     
       
    
          
          
              
          
    
          
              
             
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这里写图片描述

    配置ecache

    这个地方,必须添加一个shiro-activeSessionCache 的配置,不然就缓存不到session的数据了。

    
    
        
        
    
        
        
    
        
        
    
        
        
    
        
        
    
        
    
        
      
        
    
        
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104

    测试登录

    这里写图片描述

    参考文章

    http://blog.csdn.net/qq_32347977/article/details/51084480
    http://blog.csdn.net/lhacker/article/details/20444295
    http://blog.csdn.net/lhacker/article/details/19340757

  • 相关阅读:
    golang 运行时死锁排查和检测
    CPU上下文切换
    1236288-25-7,DSPE-PEG-FA,Folic acid PEG DSPE,磷脂-聚乙二醇-叶酸脂质体形成材料
    python之有关匿名函数和偏函数的定义,优点,以及使用方法
    Oracle查询执行计划
    C++ 背包问题——01背包
    大学解惑06 - 要求输入框内只能输入2位以内小数,怎么做?
    【python】(十九)python常用第三方库——urllib3
    Loki+Grafana查询语句
    IntelliJ IDEA 插件推荐
  • 原文地址:https://blog.csdn.net/m0_67391377/article/details/126496235