瀏覽代碼

保存登录会话到数据库

huangxiao 1 周之前
父節點
當前提交
50187018f1

+ 117 - 0
src/main/java/net/mingsoft/config/DbSessionDAO.java

@@ -0,0 +1,117 @@
+package net.mingsoft.config;
+
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.ReflectUtil;
+import net.mingsoft.base.biz.IBaseBiz;
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.mgt.SimpleSession;
+import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Stream;
+
+/**
+ * 把登录的会话保存起来
+ *
+ * @author hx
+ * @date 2025-10-31
+ */
+public class DbSessionDAO extends MemorySessionDAO {
+    /**
+     * 随便一个能操作数据库的dao
+     */
+    private IBaseBiz<?> dao;
+
+    public DbSessionDAO(IBaseBiz<?> dao) {
+        super();
+        this.dao = dao;
+        ConcurrentMap<Serializable, Session> sessions = new ConcurrentHashMap<>() {
+
+            @Override
+            public Session putIfAbsent(Serializable key, Session value) {
+                saveOrUpdate(key.toString(), (SimpleSession) value);
+                return super.putIfAbsent(key, value);
+            }
+
+            @Override
+            public Session get(Object key) {
+                Session session = super.get(key);
+                if (session == null) {
+                    // 内存查不到就从数据库里找
+                    session = query(key.toString());
+                    if (session != null) {
+                        // 如果数据库里有,那也保存一份到内存
+                        put((Serializable) key, session);
+                    }
+                }
+                return session;
+            }
+
+            @Override
+            public Session remove(Object key) {
+                delete(key.toString());
+                return super.remove(key);
+            }
+
+            @Override
+            public Collection<Session> values() {
+                return all().map(row -> (Session) row).toList();
+            }
+        };
+        ReflectUtil.setFieldValue(this, "sessions", sessions);
+    }
+
+    /**
+     * 保存或修改
+     */
+    public void saveOrUpdate(String key, SimpleSession value) {
+        byte[] session = serialize(value);
+        Date time = new Date(value.getLastAccessTime().getTime() + value.getTimeout());
+        if (query(key) == null) {
+            dao.update("INSERT INTO login_session (id, session,time) VALUES (?,?,?)", key, session, time);
+        } else {
+            dao.update("UPDATE login_session SET session =?,time=? WHERE id=?", session, time, key);
+        }
+    }
+
+    /**
+     * 查单个
+     */
+    private SimpleSession query(String key) {
+        return dao.queryForList("select * from login_session where id=?", key)
+                .stream()
+                .map(DbSessionDAO::deserialize)
+                .findFirst()
+                .orElse(null);
+    }
+
+    /**
+     * 查所有
+     */
+    private Stream<SimpleSession> all() {
+        return dao.queryForList("select * from login_session")
+                .stream()
+                .map(DbSessionDAO::deserialize);
+    }
+
+    /**
+     * 删除
+     */
+    private void delete(String key) {
+        dao.update("delete from login_session where id=?", key);
+    }
+
+    private static byte[] serialize(SimpleSession value) {
+        return ObjUtil.serialize(value);
+    }
+
+    private static SimpleSession deserialize(Map<String, Object> map) {
+        return SerializationUtils.deserialize((byte[]) map.get("session"));
+    }
+}

+ 7 - 6
src/main/java/net/mingsoft/config/ShiroConfig.java

@@ -31,6 +31,7 @@ import net.mingsoft.basic.strategy.ILoginStrategy;
 import net.mingsoft.basic.strategy.IModelStrategy;
 import net.mingsoft.basic.strategy.ManagerLoginStrategy;
 import net.mingsoft.basic.strategy.ManagerModelStrategy;
+import net.mingsoft.people.biz.IPeopleBiz;
 import net.mingsoft.people.filter.PeopleLoginFilter;
 import net.mingsoft.people.realm.PeopleAuthRealm;
 import net.mingsoft.people.realm.PeopleLoginMD5CredentialsMatcher;
@@ -41,7 +42,7 @@ import org.apache.shiro.authc.Authenticator;
 import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
 import org.apache.shiro.mgt.SecurityManager;
 import org.apache.shiro.realm.Realm;
-import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
+import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
 import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
 import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
 import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
@@ -159,14 +160,14 @@ public class ShiroConfig {
      * @return
      */
     @Bean
-    public DefaultWebSessionManager defaultWebSessionManager() {
+    public DefaultWebSessionManager defaultWebSessionManager(AbstractSessionDAO dao, SimpleCookie cookie) {
         DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
         if (serverProperties.getServlet().getSession().getTimeout() != null) {
             // 单位毫秒
             sessionManager.setGlobalSessionTimeout(serverProperties.getServlet().getSession().getTimeout().getSeconds() * 1000L);
         }
-        sessionManager.setSessionDAO(getMemorySessionDAO());
-        sessionManager.setSessionIdCookie(getSimpleCookie());
+        sessionManager.setSessionDAO(dao);
+        sessionManager.setSessionIdCookie(cookie);
         sessionManager.setSessionIdUrlRewritingEnabled(false);
         return sessionManager;
     }
@@ -183,8 +184,8 @@ public class ShiroConfig {
     }
 
     @Bean
-    public MemorySessionDAO getMemorySessionDAO() {
-        return new MemorySessionDAO();
+    public AbstractSessionDAO getMemorySessionDAO(IPeopleBiz peopleBiz) {
+        return new DbSessionDAO(peopleBiz);
     }
 
     @Bean

+ 1 - 1
src/main/resources/application.yml

@@ -2,7 +2,7 @@ server:
   port: 8080
   servlet:
     context-path: / #项目名称
-    session.timeout: P0DT60M0S #D天H小时M分钟S秒,字符T是紧跟在时分秒之前的,每个单位都必须由数字开始,且时分秒顺序不能乱
+    session.timeout: P0DT2H0M0S #D天H小时M分钟S秒,字符T是紧跟在时分秒之前的,每个单位都必须由数字开始,且时分秒顺序不能乱
     encoding:
       force: true
       charset: utf-8