From 65d26bd2be023009c3617ba5ee0ddb85442e86b6 Mon Sep 17 00:00:00 2001
From: jiangping <jp@doumee.com>
Date: 星期二, 29 八月 2023 08:57:27 +0800
Subject: [PATCH] redis缓存session

---
 server/src/main/java/doumeemes/config/shiroRedis/ShiroRedisSessionDAO.java    |  139 +++++++
 server/src/main/java/doumeemes/config/shiroRedis/ShiroCacheManager.java       |   44 ++
 server/src/main/java/doumeemes/config/shiro/ShiroCredentialsMatcher.java      |    2 
 server/src/main/java/doumeemes/config/shiroRedis/ShiroRealm.java              |  166 +++++++++
 server/src/main/java/doumeemes/config/shiro/ShiroRealm.java                   |    2 
 server/src/main/java/doumeemes/config/shiroRedis/ShiroToken.java              |   54 +++
 server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionManager.java     |   86 ++++
 server/src/main/java/doumeemes/config/shiroRedis/ShiroCredentialsMatcher.java |   47 ++
 server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionDAO.java         |  113 ++++++
 server/src/main/java/doumeemes/config/shiro/ShiroCacheManager.java            |    2 
 server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionSerializer.java  |   36 ++
 server/src/main/java/doumeemes/config/shiro/ShiroToken.java                   |    2 
 server/src/main/java/doumeemes/config/shiroRedis/ShiroAuthFilter.java         |   30 +
 server/src/main/java/doumeemes/config/shiroRedis/ShiroCache.java              |  159 ++++++++
 server/src/main/java/doumeemes/config/shiro/ShiroConfig.java                  |    2 
 server/src/main/java/doumeemes/config/shiroRedis/ShiroTokenManager.java       |   25 +
 server/src/main/java/doumeemes/config/shiro/ShiroSessionDAO.java              |    4 
 server/src/main/java/doumeemes/config/shiro/ShiroTokenManager.java            |    2 
 server/src/main/java/doumeemes/config/shiroRedis/ShiroConfig.java             |  129 +++++++
 server/src/main/java/doumeemes/config/shiro/ShiroCache.java                   |    4 
 20 files changed, 1,038 insertions(+), 10 deletions(-)

diff --git a/server/src/main/java/doumeemes/config/shiro/ShiroCache.java b/server/src/main/java/doumeemes/config/shiro/ShiroCache.java
index e91737f..2b2ec2c 100644
--- a/server/src/main/java/doumeemes/config/shiro/ShiroCache.java
+++ b/server/src/main/java/doumeemes/config/shiro/ShiroCache.java
@@ -20,9 +20,9 @@
  * @author Eva.Caesar Liu
  * @date 2022/04/18 18:12
  */
-@Scope(value = "prototype")
+//@Scope(value = "prototype")
 @Slf4j
-@Component
+//@Component
 public class ShiroCache implements Cache<Object, Serializable> {
 
     private String keyPrefix = "";
diff --git a/server/src/main/java/doumeemes/config/shiro/ShiroCacheManager.java b/server/src/main/java/doumeemes/config/shiro/ShiroCacheManager.java
index cb3ffe7..090444c 100644
--- a/server/src/main/java/doumeemes/config/shiro/ShiroCacheManager.java
+++ b/server/src/main/java/doumeemes/config/shiro/ShiroCacheManager.java
@@ -17,7 +17,7 @@
  * @date 2022/04/18 18:12
  */
 @Slf4j
-@Component
+//@Component
 public class ShiroCacheManager implements CacheManager {
 
     private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap();
diff --git a/server/src/main/java/doumeemes/config/shiro/ShiroConfig.java b/server/src/main/java/doumeemes/config/shiro/ShiroConfig.java
index 526121a..e3cc18e 100644
--- a/server/src/main/java/doumeemes/config/shiro/ShiroConfig.java
+++ b/server/src/main/java/doumeemes/config/shiro/ShiroConfig.java
@@ -22,7 +22,7 @@
  * @author Eva.Caesar Liu
  * @date 2022/04/18 18:12
  */
-@Configuration
+//@Configuration
 public class ShiroConfig {
 
     @Value("${cache.session.expire}")
diff --git a/server/src/main/java/doumeemes/config/shiro/ShiroCredentialsMatcher.java b/server/src/main/java/doumeemes/config/shiro/ShiroCredentialsMatcher.java
index 8d01643..19264b4 100644
--- a/server/src/main/java/doumeemes/config/shiro/ShiroCredentialsMatcher.java
+++ b/server/src/main/java/doumeemes/config/shiro/ShiroCredentialsMatcher.java
@@ -15,7 +15,7 @@
  * @author Eva.Caesar Liu
  * @date 2022/04/18 18:12
  */
-@Component
+//@Component
 public class ShiroCredentialsMatcher extends HashedCredentialsMatcher {
 
     @Lazy
diff --git a/server/src/main/java/doumeemes/config/shiro/ShiroRealm.java b/server/src/main/java/doumeemes/config/shiro/ShiroRealm.java
index c405ec9..c15fc49 100644
--- a/server/src/main/java/doumeemes/config/shiro/ShiroRealm.java
+++ b/server/src/main/java/doumeemes/config/shiro/ShiroRealm.java
@@ -44,7 +44,7 @@
  * @author Eva.Caesar Liu
  * @date 2022/04/18 18:12
  */
-@Component
+//@Component
 public class ShiroRealm extends AuthorizingRealm {
 
     @Lazy
diff --git a/server/src/main/java/doumeemes/config/shiro/ShiroSessionDAO.java b/server/src/main/java/doumeemes/config/shiro/ShiroSessionDAO.java
index 128383d..9b33074 100644
--- a/server/src/main/java/doumeemes/config/shiro/ShiroSessionDAO.java
+++ b/server/src/main/java/doumeemes/config/shiro/ShiroSessionDAO.java
@@ -17,9 +17,9 @@
  * @author Eva.Caesar Liu
  * @date 2022/04/18 18:12
  */
-@Data
+//@Data
 @Slf4j
-@Component
+//@Component
 public class ShiroSessionDAO implements SessionDAO {
 
     private static final String KEY_PREFIX = "shiro:session:";
diff --git a/server/src/main/java/doumeemes/config/shiro/ShiroToken.java b/server/src/main/java/doumeemes/config/shiro/ShiroToken.java
index b0fa87c..6f870b6 100644
--- a/server/src/main/java/doumeemes/config/shiro/ShiroToken.java
+++ b/server/src/main/java/doumeemes/config/shiro/ShiroToken.java
@@ -28,7 +28,7 @@
  * @author Eva.Caesar Liu
  * @date 2022/04/18 18:12
  */
-@Component
+//@Component
 public class ShiroToken extends UsernamePasswordToken {
 
     /**
diff --git a/server/src/main/java/doumeemes/config/shiro/ShiroTokenManager.java b/server/src/main/java/doumeemes/config/shiro/ShiroTokenManager.java
index 2b644dc..441a0cf 100644
--- a/server/src/main/java/doumeemes/config/shiro/ShiroTokenManager.java
+++ b/server/src/main/java/doumeemes/config/shiro/ShiroTokenManager.java
@@ -10,7 +10,7 @@
  * @author Eva.Caesar Liu
  * @date 2022/04/18 18:12
  */
-@Component
+//@Component
 public class ShiroTokenManager {
 
     String build() {
diff --git a/server/src/main/java/doumeemes/config/shiroRedis/ShiroAuthFilter.java b/server/src/main/java/doumeemes/config/shiroRedis/ShiroAuthFilter.java
new file mode 100644
index 0000000..aa80c10
--- /dev/null
+++ b/server/src/main/java/doumeemes/config/shiroRedis/ShiroAuthFilter.java
@@ -0,0 +1,30 @@
+package doumeemes.config.shiroRedis;
+
+import com.alibaba.fastjson.JSON;
+import doumeemes.core.model.ApiResponse;
+import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
+import org.springframework.http.HttpStatus;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Shiro璁よ瘉杩囨护鍣紝澶勭悊鏈璇佹儏鍐电殑鍝嶅簲
+ * @author Eva.Caesar Liu
+ * @date 2023/04/17 12:11
+ */
+public class ShiroAuthFilter extends FormAuthenticationFilter {
+
+    public ShiroAuthFilter() {
+        super();
+    }
+
+    @Override
+    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+        HttpServletResponse servletResponse = (HttpServletResponse) response;
+        servletResponse.setHeader("content-type", "application/json;charset=UTF-8");
+        servletResponse.getWriter().write(JSON.toJSONString(ApiResponse.failed(HttpStatus.UNAUTHORIZED.value(), "鏈櫥褰曟垨鐧诲綍淇℃伅宸茶繃鏈�")));
+        return Boolean.FALSE;
+    }
+}
diff --git a/server/src/main/java/doumeemes/config/shiroRedis/ShiroCache.java b/server/src/main/java/doumeemes/config/shiroRedis/ShiroCache.java
new file mode 100644
index 0000000..4527f39
--- /dev/null
+++ b/server/src/main/java/doumeemes/config/shiroRedis/ShiroCache.java
@@ -0,0 +1,159 @@
+package doumeemes.config.shiroRedis;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.cache.CacheException;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.util.CollectionUtils;
+import org.springframework.context.annotation.Scope;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.SerializationException;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Shiro缂撳瓨
+ * @author Eva.Caesar Liu
+ * @date 2023/04/17 12:11
+ */
+@Scope(value = "prototype")
+@Slf4j
+@Component
+public class ShiroCache implements Cache<Object, Serializable> {
+
+    private String keyPrefix = "";
+
+    @Resource(name="sessionRedisTemplate")
+    private RedisTemplate<Object, Serializable> redisTemplate;
+
+    public ShiroCache () {
+        log.debug("ShiroCache: new, keyPrefix = [" + keyPrefix + "]");
+    }
+
+    public ShiroCache(String keyPrefix) {
+        log.debug("ShiroCache: new, keyPrefix = [" + keyPrefix + "]");
+        this.keyPrefix = keyPrefix;
+    }
+
+    @Override
+    public Serializable get(Object key) throws CacheException {
+        if (key == null) {
+            return null;
+        }
+        return redisTemplate.opsForValue().get(getKey(key));
+    }
+
+    @Override
+    public Serializable put(Object key, Serializable value) throws CacheException {
+        if (key == null) {
+            return null;
+        }
+        redisTemplate.opsForValue().set(getKey(key), value);
+        return value;
+    }
+
+    public Serializable put(Object key, Serializable value, int timeout) throws CacheException {
+        if (key == null) {
+            return null;
+        }
+        redisTemplate.opsForValue().set(getKey(key), value, timeout, TimeUnit.SECONDS);
+        return value;
+    }
+
+    @Override
+    public void clear() throws CacheException {
+        Set<Object> keys = this.keys();
+        redisTemplate.delete(keys);
+    }
+
+    @Override
+    public int size() {
+        return this.keys().size();
+    }
+
+    @Override
+    public Set<Object> keys() {
+        Set<Object> keys = redisTemplate.keys(keyPrefix + "*");
+        if (CollectionUtils.isEmpty(keys)) {
+            return Collections.emptySet();
+        }
+        return keys;
+    }
+
+    @Override
+    public Collection<Serializable> values() {
+        Collection<Serializable> values = new ArrayList<>();
+        Set<Object> keys = this.keys();
+        if (CollectionUtils.isEmpty(keys)) {
+            return values;
+        }
+        for (Object k : keys) {
+            values.add(redisTemplate.opsForValue().get(k));
+        }
+        return values;
+    }
+
+    @Override
+    public Serializable remove(Object key) throws CacheException {
+        if (key == null) {
+            return null;
+        }
+        Serializable value = this.get(getKey(key));
+        redisTemplate.delete(getKey(key));
+        return value;
+    }
+
+    private Object getKey (Object key) {
+        if (key instanceof PrincipalCollection) {
+            return this.keyPrefix + getRedisKeyFromPrincipalIdField((PrincipalCollection)key);
+        }
+        return (key instanceof String ? (this.keyPrefix + key) : key);
+    }
+
+    /**
+     * 鑾峰彇redis cache key
+     */
+    private String getRedisKeyFromPrincipalIdField(PrincipalCollection key) {
+        Object principalObject = key.getPrimaryPrincipal();
+        if (principalObject instanceof String) {
+            return principalObject.toString();
+        } else {
+            Method pincipalIdGetter = this.getPrincipalIdGetter(principalObject);
+            return this.getIdObj(principalObject, pincipalIdGetter);
+        }
+    }
+
+    private Method getPrincipalIdGetter(Object principalObject) {
+        Method pincipalIdGetter;
+        String principalIdMethodName = this.getPrincipalIdMethodName();
+
+        try {
+            pincipalIdGetter = principalObject.getClass().getMethod(principalIdMethodName);
+            return pincipalIdGetter;
+        } catch (NoSuchMethodException e) {
+            throw new SerializationException(e.getMessage(), e);
+        }
+    }
+
+    private String getIdObj(Object principalObject, Method pincipalIdGetter) {
+        try {
+            Object idObj = pincipalIdGetter.invoke(principalObject);
+            String redisKey = idObj.toString();
+            return redisKey;
+        } catch (Exception e) {
+            throw new SerializationException(e.getMessage(), e);
+        }
+    }
+
+    private String getPrincipalIdMethodName() {
+        return "getId";
+    }
+}
diff --git a/server/src/main/java/doumeemes/config/shiroRedis/ShiroCacheManager.java b/server/src/main/java/doumeemes/config/shiroRedis/ShiroCacheManager.java
new file mode 100644
index 0000000..8c2d12f
--- /dev/null
+++ b/server/src/main/java/doumeemes/config/shiroRedis/ShiroCacheManager.java
@@ -0,0 +1,44 @@
+package doumeemes.config.shiroRedis;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.cache.CacheException;
+import org.apache.shiro.cache.CacheManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * 鑷畾涔塖hiro CacheManager
+ * @author Eva.Caesar Liu
+ * @date 2023/04/17 12:11
+ */
+@Slf4j
+@Component
+public class ShiroCacheManager implements CacheManager {
+
+    private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap();
+
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public <K, V> Cache<K, V> getCache(String name) throws CacheException {
+        log.debug("get cache, name=" + name);
+        Cache cache = this.caches.get(name);
+        if (cache == null) {
+            cache = applicationContext.getBean(ShiroCache.class, "shiro:cache:");
+            this.caches.put(name, cache);
+        }
+        return cache;
+    }
+
+    @Autowired
+    public void setApplicationContext (ApplicationContext applicationContext) {
+        if (ShiroCacheManager.applicationContext == null) {
+            ShiroCacheManager.applicationContext = applicationContext;
+        }
+    }
+}
diff --git a/server/src/main/java/doumeemes/config/shiroRedis/ShiroConfig.java b/server/src/main/java/doumeemes/config/shiroRedis/ShiroConfig.java
new file mode 100644
index 0000000..ef99566
--- /dev/null
+++ b/server/src/main/java/doumeemes/config/shiroRedis/ShiroConfig.java
@@ -0,0 +1,129 @@
+package doumeemes.config.shiroRedis;
+
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.session.mgt.SessionManager;
+import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
+import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import javax.servlet.Filter;
+import java.io.Serializable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Shiro閰嶇疆
+ * @author Eva.Caesar Liu
+ * @date 2023/04/17 12:11
+ */
+@Configuration
+public class ShiroConfig {
+
+    @Value("${cache.session.expire}")
+    private int sessionExpireTime;
+
+    @Autowired
+    private ShiroCredentialsMatcher shiroCredentialsMatcher;
+
+    @Autowired
+    private ShiroSessionDAO shiroSessionDAO;
+
+    @Autowired
+    private ShiroCacheManager shiroCacheManager;
+
+    @Autowired
+    private ShiroRealm shiroRealm;
+
+    @Bean("sessionRedisTemplate")
+    public RedisTemplate<Object, Serializable> sessionRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
+        RedisTemplate<Object, Serializable> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(redisConnectionFactory);
+        // 榛樿搴忓垪鍖栨柟寮�
+        redisTemplate.setDefaultSerializer(new StringRedisSerializer());
+        // 鍊煎簭鍒楀寲鏂瑰紡
+        ShiroSessionSerializer serializer = new ShiroSessionSerializer();
+        redisTemplate.setValueSerializer(serializer);
+        redisTemplate.setHashValueSerializer(serializer);
+        redisTemplate.afterPropertiesSet();
+        return redisTemplate;
+    }
+
+    @Bean
+    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
+        DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
+        autoProxyCreator.setProxyTargetClass(true);
+        return autoProxyCreator;
+    }
+
+    @Bean
+    public SessionManager sessionManager() {
+        ShiroSessionManager sessionManager = new ShiroSessionManager();
+        sessionManager.setSessionDAO(shiroSessionDAO);
+        return sessionManager;
+    }
+
+    @Bean
+    public SecurityManager securityManager() {
+        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+        securityManager.setRealm(shiroRealm);
+        securityManager.setSessionManager(this.sessionManager());
+        securityManager.setCacheManager(shiroCacheManager);
+        return securityManager;
+    }
+
+    @Bean
+    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
+        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
+        shiroFilterFactoryBean.setSecurityManager(securityManager);
+        Map<String, String> map = new LinkedHashMap<>();
+        // 璺緞鎷︽埅閰嶇疆
+        map.put("/web/user/login", "anon");
+        map.put("/public/uploadRichText", "anon");
+        map.put("/system/login", "anon");
+        map.put("/system/logout", "anon");
+        map.put("/common/captcha", "anon");
+        //鏀捐 scratch 鎺ュ彛
+        map.put("/web/scratch/**", "anon");
+
+        // - 鏀捐swagger
+        map.put("/doc.html", "anon");
+        map.put("/webjars/**", "anon");
+        map.put("/swagger-resources/**", "anon");
+        map.put("/v2/api-docs/**", "anon");
+        // - 鍏朵粬鎺ュ彛缁熶竴鎷︽埅
+        map.put("/**", "authc");
+        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
+        // 娣诲姞璁よ瘉杩囨护鍣�
+        Map<String, Filter> filters = new LinkedHashMap<>();
+        filters.put("authc", new ShiroAuthFilter());
+        shiroFilterFactoryBean.setFilters(filters);
+        return shiroFilterFactoryBean;
+    }
+
+    @Bean
+    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
+        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
+        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
+        return authorizationAttributeSourceAdvisor;
+    }
+
+    @Bean
+    public ShiroSessionDAO getShiroSessionDAO () {
+        shiroSessionDAO.setExpireTime(sessionExpireTime);
+        return shiroSessionDAO;
+    }
+
+    @Bean
+    public ShiroRealm getShiroRealm () {
+        shiroRealm.setCredentialsMatcher(shiroCredentialsMatcher);
+        return shiroRealm;
+    }
+}
diff --git a/server/src/main/java/doumeemes/config/shiroRedis/ShiroCredentialsMatcher.java b/server/src/main/java/doumeemes/config/shiroRedis/ShiroCredentialsMatcher.java
new file mode 100644
index 0000000..87db48b
--- /dev/null
+++ b/server/src/main/java/doumeemes/config/shiroRedis/ShiroCredentialsMatcher.java
@@ -0,0 +1,47 @@
+package doumeemes.config.shiroRedis;
+
+import doumeemes.config.shiro.ShiroToken;
+import doumeemes.core.utils.Utils;
+import doumeemes.dao.system.model.SystemUser;
+import doumeemes.service.system.SystemUserService;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+/**
+ * Shiro瀵嗙爜姣斿澶勭悊
+ * @author Eva.Caesar Liu
+ * @date 2023/04/17 12:11
+ */
+@Component
+public class ShiroCredentialsMatcher extends HashedCredentialsMatcher {
+    @Lazy
+    @Autowired
+    private SystemUserService systemUserService;
+
+    @Override
+    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
+        doumeemes.config.shiro.ShiroToken usernamePasswordToken = (ShiroToken) token;
+        SystemUser queryUserDto = new SystemUser();
+        queryUserDto.setUsername(usernamePasswordToken.getUsername());
+        queryUserDto.setDeleted(Boolean.FALSE);
+        SystemUser systemUser = systemUserService.findOne(queryUserDto);
+        if (systemUser == null) {
+            return Boolean.FALSE;
+        }
+        if(usernamePasswordToken.getDdLogin()){
+            return Boolean.TRUE;
+        }
+        if(usernamePasswordToken.getWxLogin()){
+            return Boolean.TRUE;
+        }
+        // 鍔犲瘑瀵嗙爜
+        String pwd = Utils.Secure.encryptPassword(new String(usernamePasswordToken.getPassword()), systemUser.getSalt());
+        // 姣旇緝瀵嗙爜
+        return this.equals(pwd, systemUser.getPassword());
+    }
+}
diff --git a/server/src/main/java/doumeemes/config/shiroRedis/ShiroRealm.java b/server/src/main/java/doumeemes/config/shiroRedis/ShiroRealm.java
new file mode 100644
index 0000000..ab0208d
--- /dev/null
+++ b/server/src/main/java/doumeemes/config/shiroRedis/ShiroRealm.java
@@ -0,0 +1,166 @@
+package doumeemes.config.shiroRedis;
+
+import doumeemes.core.constants.ResponseStatus;
+import doumeemes.core.exception.BusinessException;
+import doumeemes.core.model.LoginUserInfo;
+import doumeemes.core.utils.Constants;
+import doumeemes.dao.ext.dto.QueryCompanyUserExtDTO;
+import doumeemes.dao.ext.vo.CompanyExtListVO;
+import doumeemes.dao.ext.vo.CompanyUserExtListVO;
+import doumeemes.dao.ext.vo.DepartmentExtListVO;
+import doumeemes.dao.system.model.SystemDataPermission;
+import doumeemes.dao.system.model.SystemPermission;
+import doumeemes.dao.system.model.SystemRole;
+import doumeemes.dao.system.model.SystemUser;
+import doumeemes.service.ext.CompanyExtService;
+import doumeemes.service.ext.CompanyUserExtService;
+import doumeemes.service.ext.DepartmentExtService;
+import doumeemes.service.system.SystemDataPermissionService;
+import doumeemes.service.system.SystemPermissionService;
+import doumeemes.service.system.SystemRoleService;
+import doumeemes.service.system.SystemUserService;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 鑷畾涔塕ealm锛屽鐞嗚璇佸拰鏉冮檺
+ * @author Eva.Caesar Liu
+ * @date 2022/03/15 09:54
+ */
+@Component
+public class ShiroRealm extends AuthorizingRealm {
+
+    @Lazy
+    @Autowired
+    private DepartmentExtService departmentExtService;
+    @Lazy
+    @Autowired
+    private SystemDataPermissionService systemDataPermissionService;
+    @Lazy
+    @Autowired
+    private CompanyExtService companyExtService;
+    @Lazy
+    @Autowired
+    private SystemUserService systemUserService;
+    @Lazy
+    @Autowired
+    private CompanyUserExtService companyUserExtService;
+
+    @Lazy
+    @Autowired
+    private SystemRoleService systemRoleService;
+
+    @Lazy
+    @Autowired
+    private SystemPermissionService systemPermissionService;
+
+    /**
+     * 鏉冮檺澶勭悊
+     * @author Eva.Caesar Liu
+     * @date 2022/03/15 09:54
+     */
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
+        LoginUserInfo loginUserInfo = (LoginUserInfo)principalCollection.getPrimaryPrincipal();
+        // 璁剧疆鐢ㄦ埛瑙掕壊鍜屾潈闄�
+        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
+        authorizationInfo.addRoles(loginUserInfo.getRoles());
+        authorizationInfo.addStringPermissions(loginUserInfo.getPermissions());
+        return authorizationInfo;
+    }
+
+    /**
+     * 璁よ瘉澶勭悊
+     * @author Eva.Caesar Liu
+     * @date 2022/03/15 09:54
+     */
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+        // 鑾峰彇鐢ㄦ埛鍚�
+        ShiroToken authenticationToken =(ShiroToken) token;
+        String username = authenticationToken.getPrincipal().toString();
+        boolean isDdLogin = authenticationToken.getDdLogin();
+        // 鏍规嵁鐢ㄦ埛鍚嶆煡璇㈢敤鎴峰璞�
+        SystemUser queryDto = new SystemUser();
+        queryDto.setUsername(username);
+        queryDto.setDeleted(Boolean.FALSE);
+        SystemUser user = systemUserService.findOne(queryDto);
+        if (user == null) {
+            return null;
+        }
+        SystemRole role = new SystemRole();
+        SystemPermission per = new SystemPermission();
+        DepartmentExtListVO rootDepart = null,comDepart=null, depart = null;
+        List<Integer> dpList = null;
+        CompanyExtListVO com = null;
+        CompanyUserExtListVO cu =null;
+        if(Constants.equalsInteger(user.getType(),Constants.PlatType.admin)){
+            //濡傛灉鏄钩鍙扮敤鎴�
+            role.setType(Constants.ROLETYPE.plat);
+            per.setType(Constants.PlatType.admin);
+        }else{
+            if(authenticationToken.getCompanyId() == null){
+                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"瀵逛笉璧凤紝璇ヨ处鎴峰垹闄わ紒");
+            }
+            com = companyExtService.getModelById(authenticationToken.getCompanyId());
+            if(com == null || Constants.equalsInteger( com.getDeleted(),Constants.ONE)){
+                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"瀵逛笉璧凤紝璇ヨ处鎴峰垹闄わ紒璇疯仈绯荤鐞嗗憳");
+            }
+            if(Constants.equalsInteger( com.getStatus(),Constants.ZERO) ){
+                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"瀵逛笉璧凤紝璇ヤ紒涓氬凡绂佺敤锛�");
+            }
+            if(com.getOepnValidDate() != null && com.getOepnValidDate().before(new Date())){
+                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"瀵逛笉璧凤紝璇ヤ紒涓氬凡杩囦娇鐢ㄦ湁鏁堟湡锛�");
+            }
+            //濡傛灉鏄紒涓氱敤鎴�
+            QueryCompanyUserExtDTO c =new QueryCompanyUserExtDTO();
+            c.setUserId(user.getId());
+            c.setDeleted(Constants.ZERO);
+            c.setCompanyId(authenticationToken.getCompanyId());
+            cu = companyUserExtService.selectOne(c);
+            if(cu == null){
+                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"瀵逛笉璧凤紝璇ヤ紒涓氱敤鎴蜂笉瀛樺湪锛�");
+            }
+            if(Constants.equalsInteger(cu.getStatus(),Constants.ONE)){
+                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"瀵逛笉璧凤紝璇ヤ紒涓氱敤鎴峰凡绂佺敤锛�");
+            }
+            rootDepart = departmentExtService.getModelById(c.getCompanyId(),cu.getRootDepartId());
+            comDepart = departmentExtService.getModelById(c.getCompanyId(),cu.getComDepartId());
+            depart = departmentExtService.getModelById(c.getCompanyId(),cu.getDepartmentId());
+            if(rootDepart == null || comDepart == null || depart==null){
+                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"瀵逛笉璧凤紝璇ヤ紒涓氱敤鎴疯处鎴峰紓甯革紒");
+            }
+            role.setCompanyId(authenticationToken.getCompanyId());
+            role.setType(Constants.ROLETYPE.com);
+            per.setType(Constants.PlatType.company);
+            per.setRoleType(Constants.ROLETYPE.com);
+            per.setCompanyId(authenticationToken.getCompanyId());
+            SystemRole rt = new SystemRole();
+            rt.setType(Constants.ROLETYPE.com);
+            rt.setCompanyId(c.getCompanyId());
+            //鏁版嵁閮ㄩ棬鏉冮檺闆嗗悎
+            dpList =systemDataPermissionService.selectHighRole(new SystemDataPermission(),rt,user,depart);
+
+        }
+        // 鑾峰彇鐧诲綍鐢ㄦ埛淇℃伅
+        List<SystemRole> roles = systemRoleService.findByUserModel(user.getId(),role);
+        List<SystemPermission> permissions = systemPermissionService.findByUserModel(user.getId(),per);
+        LoginUserInfo userInfo = LoginUserInfo.from(user, roles, permissions,com,rootDepart,comDepart,depart,dpList,cu);
+        // 楠岃瘉鐢ㄦ埛
+        return new SimpleAuthenticationInfo(userInfo, user.getPassword(), this.getName());
+    }
+
+}
diff --git a/server/src/main/java/doumeemes/config/shiroRedis/ShiroRedisSessionDAO.java b/server/src/main/java/doumeemes/config/shiroRedis/ShiroRedisSessionDAO.java
new file mode 100644
index 0000000..fb2fe30
--- /dev/null
+++ b/server/src/main/java/doumeemes/config/shiroRedis/ShiroRedisSessionDAO.java
@@ -0,0 +1,139 @@
+package doumeemes.config.shiroRedis;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.SerializationUtils;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.UnknownSessionException;
+import org.apache.shiro.session.mgt.SimpleSession;
+import org.apache.shiro.session.mgt.eis.SessionDAO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.concurrent.TimeUnit;
+
+//@Component
+@Slf4j
+@SuppressWarnings({ "rawtypes", "unchecked" })
+public class ShiroRedisSessionDAO  implements SessionDAO {
+// Session瓒呮椂鏃堕棿锛屽崟浣嶄负姣
+private static final String KEY_PREFIX = "shiro:session:";
+    private long expireTime = 120000;
+    @Autowired
+    private ShiroTokenManager shiroTokenManager;
+    @Autowired
+    private RedisTemplate redisTemplate;// Redis鎿嶄綔绫伙紝瀵硅繖涓娇鐢ㄤ笉鐔熸倝鐨勶紝鍙互鍙傝�冨墠闈㈢殑鍗氬
+
+    public ShiroRedisSessionDAO() {
+
+        super();
+
+    }
+
+    public ShiroRedisSessionDAO(long expireTime, StringRedisTemplate redisTemplate) {
+
+        super();
+
+        this.expireTime = expireTime;
+
+        this.redisTemplate = redisTemplate;
+
+    }
+
+    @Override // 鏇存柊session
+
+    public void update(Session session) throws UnknownSessionException {
+
+        System.out.println("===============update================");
+
+        if (session == null || session.getId() == null) {
+            return;
+        }
+        session.setTimeout(expireTime);
+        byte[] bytes = SerializationUtils.serialize((Serializable) session);
+        redisTemplate.opsForValue().set(KEY_PREFIX+session.getId(), bytes, expireTime, TimeUnit.MILLISECONDS);
+    }
+
+    @Override // 鍒犻櫎session
+
+    public void delete(Session session) {
+
+        System.out.println("===============delete================");
+
+        if (null == session) {
+
+            return;
+
+        }
+
+        redisTemplate.opsForValue().getOperations().delete(KEY_PREFIX+session.getId());
+
+    }
+
+    @Override// 鑾峰彇娲昏穬鐨剆ession锛屽彲浠ョ敤鏉ョ粺璁″湪绾夸汉鏁帮紝濡傛灉瑕佸疄鐜拌繖涓姛鑳斤紝鍙互鍦ㄥ皢session鍔犲叆redis鏃舵寚瀹氫竴涓猻ession鍓嶇紑锛岀粺璁$殑鏃跺�欏垯浣跨敤keys("session-prefix*")鐨勬柟寮忔潵妯$硦鏌ユ壘redis涓墍鏈夌殑session闆嗗悎
+    public Collection getActiveSessions() {
+
+        System.out.println("==============getActiveSessions=================");
+
+        return redisTemplate.keys("*");
+
+    }
+
+    @Override
+    public Serializable create(Session session) {
+
+        System.out.println("===============doCreate================");
+
+        if (session == null) {
+            log.error("session is null");
+            throw new UnknownSessionException("session is null");
+        }
+        Serializable sessionId = shiroTokenManager.build();
+        ((SimpleSession)session).setId(sessionId);
+        byte[] bytes = SerializationUtils.serialize((Serializable) session);
+        redisTemplate.opsForValue().set(session.getId(), bytes, expireTime, TimeUnit.MILLISECONDS);
+        return sessionId;
+
+    }
+    public Session readSession(Serializable sessionId) throws UnknownSessionException{
+        if (sessionId == null) {
+            log.warn("session id is null");
+            return null;
+        }
+        if (sessionId instanceof String) {
+            // 瀵筍essionId杩涜楠岃瘉锛堝彲鐢ㄤ簬闃叉Session鎹曡幏銆佹毚鍔涙崟鎹夌瓑涓�绯诲垪瀹夊叏闂锛屾渶缁堝畨鍏ㄦ�у彇鍐充簬check濡備綍瀹炵幇锛�
+            shiroTokenManager.check((String) sessionId);
+        }
+        log.debug("read session from cache");
+
+        SimpleSession simpleSession = (SimpleSession) SerializationUtils.deserialize((byte[])redisTemplate.opsForValue().get(KEY_PREFIX+sessionId));
+       return simpleSession;
+
+    }
+
+    public long getExpireTime() {
+
+        return expireTime;
+
+    }
+
+    public void setExpireTime(long expireTime) {
+
+        this.expireTime = expireTime;
+
+    }
+
+    public RedisTemplate getRedisTemplate() {
+
+        return redisTemplate;
+
+    }
+
+    public void setRedisTemplate(RedisTemplate redisTemplate) {
+
+        this.redisTemplate = redisTemplate;
+
+    }
+}
diff --git a/server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionDAO.java b/server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionDAO.java
new file mode 100644
index 0000000..dd3914f
--- /dev/null
+++ b/server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionDAO.java
@@ -0,0 +1,113 @@
+package doumeemes.config.shiroRedis;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.UnknownSessionException;
+import org.apache.shiro.session.mgt.SimpleSession;
+import org.apache.shiro.session.mgt.eis.SessionDAO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * 鑷畾涔塖hiro SessionDAO锛屽皢浼氳瘽淇℃伅瀛樺叆缂撳瓨涓�
+ * @author Eva.Caesar Liu
+ * @date 2023/04/17 12:11
+ */
+@Data
+@Slf4j
+@Component
+public class ShiroSessionDAO implements SessionDAO {
+
+    private static final String KEY_PREFIX = "shiro:session:";
+
+    @Autowired
+    private ShiroCache shiroCache;
+
+    private int expireTime = 60 * 60 * 24;
+
+    @Autowired
+    private ShiroTokenManager shiroTokenManager;
+
+    @Override
+    public Serializable create(Session session) {
+        if (session == null) {
+            log.error("session is null");
+            throw new UnknownSessionException("session is null");
+        }
+        Serializable sessionId = shiroTokenManager.build();
+        ((SimpleSession)session).setId(sessionId);
+        this.saveSession(session);
+        return sessionId;
+    }
+
+    @Override
+    public Session readSession(Serializable sessionId) throws UnknownSessionException{
+        if (sessionId == null) {
+            log.warn("session id is null");
+            return null;
+        }
+        if (sessionId instanceof String) {
+            // 瀵筍essionId杩涜楠岃瘉锛堝彲鐢ㄤ簬闃叉Session鎹曡幏銆佹毚鍔涙崟鎹夌瓑涓�绯诲垪瀹夊叏闂锛屾渶缁堝畨鍏ㄦ�у彇鍐充簬check濡備綍瀹炵幇锛�
+            shiroTokenManager.check((String) sessionId);
+        }
+        log.debug("read session from cache");
+        Session session = getSessionFromCache(sessionId);
+        if (session == null) {
+            throw new UnknownSessionException("There is no session with id [" + sessionId + "]");
+        }
+        return session;
+    }
+
+    @Override
+    public void update(Session session) throws UnknownSessionException {
+        this.saveSession(session);
+    }
+
+    @Override
+    public void delete(Session session) {
+        if (session != null && session.getId() != null) {
+            shiroCache.remove(KEY_PREFIX + session.getId());
+        }
+    }
+
+    @Override
+    public Collection<Session> getActiveSessions() {
+        Set<Session> sessions = new HashSet<>();
+        Set<Object> keys = shiroCache.keys();
+        if (keys != null && keys.size() > 0) {
+            Iterator iter = keys.iterator();
+            while(iter.hasNext()) {
+                sessions.add((Session) shiroCache.get(iter.next()));
+            }
+        }
+        return sessions;
+    }
+
+    private void saveSession(Session session) throws UnknownSessionException {
+        if (session == null || session.getId() == null) {
+            log.error("session or session id is null");
+            throw new UnknownSessionException("session or session id is null");
+        }
+        shiroCache.put(KEY_PREFIX + session.getId(), (SimpleSession)session, expireTime);
+    }
+
+    private Session getSessionFromCache (Serializable sessionId) {
+        Serializable object = shiroCache.get(KEY_PREFIX + sessionId);
+        Session session = null;
+        if (object != null) {
+            session = (Session)shiroCache.get(KEY_PREFIX + sessionId);
+        }
+        return session;
+    }
+
+    public void setExpireTime (int expireTime) {
+        this.expireTime = expireTime;
+    }
+}
diff --git a/server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionManager.java b/server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionManager.java
new file mode 100644
index 0000000..b64d773
--- /dev/null
+++ b/server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionManager.java
@@ -0,0 +1,86 @@
+package doumeemes.config.shiroRedis;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.mgt.DefaultSessionManager;
+import org.apache.shiro.session.mgt.SessionContext;
+import org.apache.shiro.session.mgt.SessionKey;
+import org.apache.shiro.web.servlet.Cookie;
+import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
+import org.apache.shiro.web.servlet.SimpleCookie;
+import org.apache.shiro.web.session.mgt.WebSessionManager;
+import org.apache.shiro.web.util.WebUtils;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.Serializable;
+
+/**
+ * 鑷畾涔変細璇濈鐞嗗櫒
+ * @author Eva.Caesar Liu
+ * @date 2023/04/17 12:11
+ */
+@Slf4j
+public class ShiroSessionManager extends DefaultSessionManager implements WebSessionManager {
+
+    private static final String AUTH_TOKEN = "eva-auth-token";
+
+    @Override
+    protected void onStart(Session session, SessionContext context) {
+        super.onStart(session, context);
+        if (!WebUtils.isHttp(context)) {
+            log.debug("SessionContext argument is not Http compatible or does not have an Http request/response pair. No session ID cookie will be set.");
+            return;
+        }
+        HttpServletRequest request = WebUtils.getHttpRequest(context);
+        HttpServletResponse response = WebUtils.getHttpResponse(context);
+        Serializable sessionId = session.getId();
+        this.storeSessionId(sessionId, request, response);
+        request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);
+        request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
+    }
+
+    @Override
+    public Serializable getSessionId(SessionKey key) {
+        Serializable sessionId = super.getSessionId(key);
+        if (sessionId == null && WebUtils.isWeb(key)) {
+            ServletRequest servletRequest = WebUtils.getRequest(key);
+            if (!(servletRequest instanceof HttpServletRequest)) {
+                log.trace("Can not get sessionId from header, the request is not HttpServletRequest");
+                return null;
+            }
+            HttpServletRequest request = (HttpServletRequest) servletRequest;
+            // 浠巆ookie涓幏鍙栬璇�
+            javax.servlet.http.Cookie[] cookies = request.getCookies();
+            if (cookies != null) {
+                for (javax.servlet.http.Cookie cookie : cookies) {
+                    if (AUTH_TOKEN.equals(cookie.getName())) {
+                        return cookie.getValue();
+                    }
+                }
+            }
+            // 浠巋eader涓幏鍙栬璇�
+            return request.getHeader(AUTH_TOKEN);
+        }
+        return sessionId;
+    }
+
+    @Override
+    public boolean isServletContainerSessions() {
+        return false;
+    }
+
+    private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {
+        if (currentId == null) {
+            String msg = "sessionId cannot be null when persisting for subsequent requests.";
+            throw new IllegalArgumentException(msg);
+        }
+        Cookie cookie = new SimpleCookie(AUTH_TOKEN);
+        cookie.setHttpOnly(false);
+        String idString = currentId.toString();
+        cookie.setValue(idString);
+        cookie.saveTo(request, response);
+        log.trace("Set session ID cookie for session with id {}", idString);
+    }
+}
diff --git a/server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionSerializer.java b/server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionSerializer.java
new file mode 100644
index 0000000..cd72d2d
--- /dev/null
+++ b/server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionSerializer.java
@@ -0,0 +1,36 @@
+package doumeemes.config.shiroRedis;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.shiro.codec.Base64;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.SerializationException;
+
+import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Session搴忓垪鍖�
+ * @author Eva.Caesar Liu
+ * @date 2023/04/17 12:11
+ */
+public class ShiroSessionSerializer implements RedisSerializer<Serializable> {
+
+    @Override
+    public byte[] serialize(Serializable obj) throws SerializationException {
+        if (obj == null) {
+            return new byte[0];
+        }
+        String sessionBase64 = Base64.encodeToString(SerializationUtils.serialize(obj));
+        return sessionBase64.getBytes(StandardCharsets.UTF_8);
+    }
+
+    @Override
+    public Serializable deserialize(byte[] bytes) throws SerializationException {
+        if (bytes == null || bytes.length == 0) {
+            return null;
+        }
+        String sessionString = new String(bytes, StandardCharsets.UTF_8);
+        byte[] sessionBytes = Base64.decode(sessionString);
+        return SerializationUtils.deserialize(sessionBytes);
+    }
+}
diff --git a/server/src/main/java/doumeemes/config/shiroRedis/ShiroToken.java b/server/src/main/java/doumeemes/config/shiroRedis/ShiroToken.java
new file mode 100644
index 0000000..92a7314
--- /dev/null
+++ b/server/src/main/java/doumeemes/config/shiroRedis/ShiroToken.java
@@ -0,0 +1,54 @@
+package doumeemes.config.shiroRedis;
+
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.springframework.stereotype.Component;
+
+/**
+ * 鑷畾涔塗oken 锛屽鐞嗚璇佸拰鏉冮檺
+ * @author Eva.Caesar Liu
+ * @date 2022/04/18 18:12
+ */
+@Component
+public class ShiroToken extends UsernamePasswordToken {
+
+    /**
+     * 鍏徃ID
+     */
+    Integer companyId;
+    Boolean isDdLogin;
+    Boolean isWxLogin;
+
+    public ShiroToken() {
+    }
+    public ShiroToken(Integer companyId, String username, String password, boolean isDdLogin, boolean isWxLogin) {
+        super(username,  password, false, (String)null);
+        this.companyId = companyId;
+        this.isDdLogin = isDdLogin;
+        this.isWxLogin = isWxLogin;
+    }
+
+    public Boolean getDdLogin() {
+        return isDdLogin;
+    }
+
+    public void setDdLogin(Boolean ddLogin) {
+        isDdLogin = ddLogin;
+    }
+
+
+    public Boolean getWxLogin() {
+        return isWxLogin;
+    }
+
+    public void setWxLogin(Boolean wxLogin) {
+        isWxLogin = wxLogin;
+    }
+
+    public Integer getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Integer companyId) {
+        this.companyId = companyId;
+    }
+}
diff --git a/server/src/main/java/doumeemes/config/shiroRedis/ShiroTokenManager.java b/server/src/main/java/doumeemes/config/shiroRedis/ShiroTokenManager.java
new file mode 100644
index 0000000..c53c3fa
--- /dev/null
+++ b/server/src/main/java/doumeemes/config/shiroRedis/ShiroTokenManager.java
@@ -0,0 +1,25 @@
+package doumeemes.config.shiroRedis;
+
+import doumeemes.core.exception.UnSafeSessionException;
+import org.springframework.stereotype.Component;
+
+import java.util.UUID;
+
+/**
+ * 榛樿Token绠$悊鍣�
+ * @author Eva.Caesar Liu
+ * @date 2023/04/17 12:11
+ */
+@Component
+public class ShiroTokenManager {
+
+    String build() {
+        return UUID.randomUUID().toString();
+    }
+
+    void check(String token) throws UnSafeSessionException {
+        if (token == null || token.length() != 36) {
+            throw new UnSafeSessionException();
+        }
+    }
+}

--
Gitblit v1.9.3