summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshizhendong <[email protected]>2023-06-27 10:59:03 +0800
committershizhendong <[email protected]>2023-06-27 10:59:03 +0800
commit81b3af82a0df352e3969b015dd4dd22bde0a005c (patch)
tree0122db036c8646d2677bd6bcd3471cd942aa5e27
parenta69a38c9396d070939168ee50b2588685385f19b (diff)
fix: NEZ-2918 shiro-redis 通过 redisTemplate 操作 redis
-rw-r--r--nz-admin/src/main/java/com/nis/common/config/ShiroConfig.java93
-rw-r--r--nz-admin/src/main/java/com/nis/modules/sys/shiro/MyRedisManager.java76
-rw-r--r--nz-admin/src/main/java/com/nis/modules/sys/shiro/MyRedisSessionDAO.java305
3 files changed, 421 insertions, 53 deletions
diff --git a/nz-admin/src/main/java/com/nis/common/config/ShiroConfig.java b/nz-admin/src/main/java/com/nis/common/config/ShiroConfig.java
index 5c94a31b..0853bb5b 100644
--- a/nz-admin/src/main/java/com/nis/common/config/ShiroConfig.java
+++ b/nz-admin/src/main/java/com/nis/common/config/ShiroConfig.java
@@ -1,13 +1,18 @@
package com.nis.common.config;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import javax.servlet.Filter;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletResponse;
-
+import Aladdin.HaspStatus;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.nis.common.interceptor.TokenCheckFilter;
+import com.nis.common.utils.*;
+import com.nis.modules.metric.dto.NezhaMetrics;
+import com.nis.modules.sys.dao.SysApiKeyDao;
+import com.nis.modules.sys.dao.SysUserDao;
+import com.nis.modules.sys.entity.SysConfigEntity;
+import com.nis.modules.sys.service.LicenseService;
+import com.nis.modules.sys.service.SysConfigService;
+import com.nis.modules.sys.shiro.*;
+import io.micrometer.core.instrument.MeterRegistry;
import org.apache.catalina.connector.Connector;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
@@ -16,7 +21,6 @@ import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
-import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -27,66 +31,55 @@ import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerF
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.nis.common.interceptor.TokenCheckFilter;
-import com.nis.common.utils.Constant;
-import com.nis.common.utils.R;
-import com.nis.common.utils.RCode;
-import com.nis.common.utils.Tool;
-import com.nis.common.utils.ToolUtil;
-import com.nis.modules.metric.dto.NezhaMetrics;
-import com.nis.modules.sys.dao.SysApiKeyDao;
-import com.nis.modules.sys.dao.SysUserDao;
-import com.nis.modules.sys.entity.SysConfigEntity;
-import com.nis.modules.sys.service.LicenseService;
-import com.nis.modules.sys.service.SysConfigService;
-import com.nis.modules.sys.shiro.MySessionManager;
-import com.nis.modules.sys.shiro.ShiroUtils;
-import com.nis.modules.sys.shiro.UserRealm;
-
-import Aladdin.HaspStatus;
-import cn.hutool.core.util.StrUtil;
-import io.micrometer.core.instrument.MeterRegistry;
+import javax.servlet.Filter;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+import java.util.LinkedHashMap;
+import java.util.Map;
/**
* Shiro的配置文件
- *
*/
@Configuration
@DependsOn(value = { "mybatisPlusConfig", "redisConfig" })
public class ShiroConfig {
+ @Value("${compileType:release}")
+ private String compileType;
+
+ @Value("${vendorCode}")
+ private String vendorCode;
+
@Autowired
- private RedisConfig config;
+ private LicenseService licenseService;
@Autowired
- private RedisTemplate<String, String> redisTemplate;
+ private SysConfigService sysconfigService;
@Autowired
private SysUserDao sysUserDao;
@Autowired
- private SysConfigService sysconfigService;
+ private SysApiKeyDao sysApiKeyDao;
@Autowired
- private SysApiKeyDao sysApiKeyDao;
-
- @Value("${compileType:release}")
- private String compileType;
- @Value("${vendorCode}")
- private String vendorCode;
+ private NezhaMetrics nezhaMetrics;
+
@Autowired
- private NezhaMetrics nezhaMetrics;
+ private MeterRegistry meterRegistry;
- @Autowired
- private MeterRegistry meterRegistry;
@Autowired
- private LicenseService licenseService;
-
+ private RedisTemplate<String, String> redisTemplate;
+
+ @Autowired
+ private RedisConnectionFactory redisConnectionFactory;
+
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
@@ -220,14 +213,8 @@ public class ShiroConfig {
*
* @return
*/
- public RedisManager redisManager() {
- RedisManager redisManager = new RedisManager();
- redisManager.setHost(config.getRedisHost() + ":" + config.getRedisPort());
- redisManager.setTimeout(Tool.NumberUtil.parseInt(Tool.StrUtil.toString(config.getRedisTimeout())));
- redisManager.setDatabase(config.getRedisDatabase());
- if (Tool.StrUtil.isNotBlank(config.getRedisPin())) {
- redisManager.setPassword(config.getRedisPin());
- }
+ public MyRedisManager redisManager() {
+ MyRedisManager redisManager = new MyRedisManager(redisConnectionFactory);
return redisManager;
}
@@ -255,7 +242,7 @@ public class ShiroConfig {
@Bean
public RedisSessionDAO redisSessionDAO() {
Integer loginExpiration = getTimeOutData();
- RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
+ MyRedisSessionDAO redisSessionDAO = new MyRedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
redisSessionDAO.setExpire(loginExpiration * 60);
redisSessionDAO.setKeyPrefix(ShiroUtils.REDIS_KEYPREFIX);
diff --git a/nz-admin/src/main/java/com/nis/modules/sys/shiro/MyRedisManager.java b/nz-admin/src/main/java/com/nis/modules/sys/shiro/MyRedisManager.java
new file mode 100644
index 00000000..98271bf5
--- /dev/null
+++ b/nz-admin/src/main/java/com/nis/modules/sys/shiro/MyRedisManager.java
@@ -0,0 +1,76 @@
+package com.nis.modules.sys.shiro;
+
+import com.nis.common.utils.Tool;
+import org.apache.shiro.session.Session;
+import org.crazycake.shiro.IRedisManager;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 自定义 redis manager
+ *
+ * @author ThinkPad
+ */
+public class MyRedisManager implements IRedisManager {
+
+ private RedisTemplate<String, Object> redisTemplate;
+
+ public MyRedisManager(RedisConnectionFactory factory) {
+ redisTemplate = new RedisTemplate<>();
+
+ redisTemplate.setKeySerializer(new StringRedisSerializer());
+ redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
+
+ redisTemplate.setConnectionFactory(factory);
+ redisTemplate.afterPropertiesSet();
+ }
+
+ @Override
+ public byte[] get(byte[] key) {
+ return null;
+ }
+
+ @Override
+ public byte[] set(byte[] key, byte[] value, int expire) {
+ return null;
+ }
+
+ @Override
+ public void del(byte[] key) {
+ }
+
+ @Override
+ public Long dbSize(byte[] pattern) {
+ return 16L;
+ }
+
+ @Override
+ public Set<byte[]> keys(byte[] pattern) {
+ return Tool.CollUtil.newHashSet();
+ }
+
+ public Object get(String key) {
+ ValueOperations<String, Object> valueOperations = this.redisTemplate.opsForValue();
+ return valueOperations.get(key);
+ }
+
+ public Session set(String key, Session value, int expire) {
+ ValueOperations<String, Object> opsForValue = this.redisTemplate.opsForValue();
+ opsForValue.set(key, value, expire, TimeUnit.SECONDS);
+ return value;
+ }
+
+ public void del(String key) {
+ this.redisTemplate.delete(key);
+ }
+
+ public Set<String> keys(String pattern) {
+ return this.redisTemplate.keys(pattern);
+ }
+}
diff --git a/nz-admin/src/main/java/com/nis/modules/sys/shiro/MyRedisSessionDAO.java b/nz-admin/src/main/java/com/nis/modules/sys/shiro/MyRedisSessionDAO.java
new file mode 100644
index 00000000..8fedc6aa
--- /dev/null
+++ b/nz-admin/src/main/java/com/nis/modules/sys/shiro/MyRedisSessionDAO.java
@@ -0,0 +1,305 @@
+package com.nis.modules.sys.shiro;
+
+import cn.hutool.log.Log;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.UnknownSessionException;
+import org.apache.shiro.session.mgt.eis.SessionDAO;
+import org.crazycake.shiro.IRedisManager;
+import org.crazycake.shiro.RedisSessionDAO;
+import org.crazycake.shiro.common.SessionInMemory;
+import org.springframework.data.redis.serializer.SerializationException;
+
+import java.io.Serializable;
+import java.util.*;
+
+public class MyRedisSessionDAO extends RedisSessionDAO implements SessionDAO {
+
+ private static final Log logger = Log.get();
+
+ private static final String DEFAULT_SESSION_KEY_PREFIX = "shiro:session:";
+ private String keyPrefix = "shiro:session:";
+ private static final long DEFAULT_SESSION_IN_MEMORY_TIMEOUT = 1000L;
+ private long sessionInMemoryTimeout = 1000L;
+ private static final boolean DEFAULT_SESSION_IN_MEMORY_ENABLED = true;
+ private boolean sessionInMemoryEnabled = true;
+ private static ThreadLocal sessionsInThread = new ThreadLocal();
+ private static final int DEFAULT_EXPIRE = -2;
+ private static final int NO_EXPIRE = -1;
+ private int expire = -2;
+ private static final int MILLISECONDS_IN_A_SECOND = 1000;
+ private MyRedisManager redisManager;
+
+ public MyRedisSessionDAO() {
+ }
+
+ @Override
+ public void update(Session session) throws UnknownSessionException {
+ if (this.sessionInMemoryEnabled) {
+ this.removeExpiredSessionInMemory();
+ }
+
+ this.saveSession(session);
+ if (this.sessionInMemoryEnabled) {
+ this.setSessionToThreadLocal(session.getId(), session);
+ }
+
+ }
+
+ private void saveSession(Session session) throws UnknownSessionException {
+ if (session != null && session.getId() != null) {
+ String key;
+ Session value;
+ try {
+ key = this.getRedisSessionKey(session.getId());
+ value = session;
+ } catch (SerializationException var5) {
+ logger.error("serialize session error. session id=" + session.getId());
+ throw new UnknownSessionException(var5);
+ }
+
+ if (this.expire == -2) {
+ this.redisManager.set(key, value, (int) (session.getTimeout() / 1000L));
+ } else {
+ if (this.expire != -1 && (long) (this.expire * 1000) < session.getTimeout()) {
+ logger.warn("Redis session expire time: " + this.expire * 1000 + " is less than Session timeout: " + session.getTimeout() + " . It may cause some problems.");
+ }
+
+ this.redisManager.set(key, value, this.expire);
+ }
+ } else {
+ logger.error("session or session id is null");
+ throw new UnknownSessionException("session or session id is null");
+ }
+ }
+
+ @Override
+ public void delete(Session session) {
+ if (this.sessionInMemoryEnabled) {
+ this.removeExpiredSessionInMemory();
+ }
+
+ if (session != null && session.getId() != null) {
+ if (this.sessionInMemoryEnabled) {
+ this.delSessionFromThreadLocal(session.getId());
+ }
+
+ try {
+ this.redisManager.del(this.getRedisSessionKey(session.getId()));
+ } catch (SerializationException var3) {
+ logger.error("delete session error. session id=" + session.getId());
+ }
+
+ } else {
+ logger.error("session or session id is null");
+ }
+ }
+
+ @Override
+ public Collection<Session> getActiveSessions() {
+ if (this.sessionInMemoryEnabled) {
+ this.removeExpiredSessionInMemory();
+ }
+
+ HashSet sessions = new HashSet();
+
+ try {
+ Set<String> keys = this.redisManager.keys(this.keyPrefix + "*");
+ if (keys != null && keys.size() > 0) {
+ Iterator<String> var3 = keys.iterator();
+ while (var3.hasNext()) {
+ String key = var3.next();
+ Session s = (Session) this.redisManager.get(key);
+ sessions.add(s);
+ }
+ }
+ } catch (SerializationException var6) {
+ logger.error("get active sessions error.");
+ }
+
+ return sessions;
+ }
+
+ @Override
+ protected Serializable doCreate(Session session) {
+ if (this.sessionInMemoryEnabled) {
+ this.removeExpiredSessionInMemory();
+ }
+
+ if (session == null) {
+ logger.error("session is null");
+ throw new UnknownSessionException("session is null");
+ } else {
+ Serializable sessionId = this.generateSessionId(session);
+ this.assignSessionId(session, sessionId);
+ this.saveSession(session);
+ return sessionId;
+ }
+ }
+
+ @Override
+ protected Session doReadSession(Serializable sessionId) {
+ if (this.sessionInMemoryEnabled) {
+ this.removeExpiredSessionInMemory();
+ }
+
+ if (sessionId == null) {
+ logger.warn("session id is null");
+ return null;
+ } else {
+ Session session;
+ if (this.sessionInMemoryEnabled) {
+ session = this.getSessionFromThreadLocal(sessionId);
+ if (session != null) {
+ return session;
+ }
+ }
+
+ session = null;
+
+ try {
+ String sessionRedisKey = this.getRedisSessionKey(sessionId);
+ logger.debug("read session: " + sessionRedisKey + " from Redis");
+ session = (Session) this.redisManager.get(sessionRedisKey);
+ if (this.sessionInMemoryEnabled) {
+ this.setSessionToThreadLocal(sessionId, session);
+ }
+ } catch (SerializationException var4) {
+ logger.error("read session error. sessionId: " + sessionId);
+ }
+
+ return session;
+ }
+ }
+
+ private void setSessionToThreadLocal(Serializable sessionId, Session session) {
+ this.initSessionsInThread();
+ Map<Serializable, SessionInMemory> sessionMap = (Map) sessionsInThread.get();
+ sessionMap.put(sessionId, this.createSessionInMemory(session));
+ }
+
+ private void delSessionFromThreadLocal(Serializable sessionId) {
+ Map<Serializable, SessionInMemory> sessionMap = (Map) sessionsInThread.get();
+ if (sessionMap != null) {
+ sessionMap.remove(sessionId);
+ }
+ }
+
+ private SessionInMemory createSessionInMemory(Session session) {
+ SessionInMemory sessionInMemory = new SessionInMemory();
+ sessionInMemory.setCreateTime(new Date());
+ sessionInMemory.setSession(session);
+ return sessionInMemory;
+ }
+
+ private void initSessionsInThread() {
+ Map<Serializable, SessionInMemory> sessionMap = (Map) sessionsInThread.get();
+ if (sessionMap == null) {
+ sessionMap = new HashMap();
+ sessionsInThread.set(sessionMap);
+ }
+
+ }
+
+ private void removeExpiredSessionInMemory() {
+ Map<Serializable, SessionInMemory> sessionMap = (Map) sessionsInThread.get();
+ if (sessionMap != null) {
+ Iterator it = sessionMap.keySet().iterator();
+
+ while (it.hasNext()) {
+ Serializable sessionId = (Serializable) it.next();
+ SessionInMemory sessionInMemory = (SessionInMemory) sessionMap.get(sessionId);
+ if (sessionInMemory == null) {
+ it.remove();
+ } else {
+ long liveTime = this.getSessionInMemoryLiveTime(sessionInMemory);
+ if (liveTime > this.sessionInMemoryTimeout) {
+ it.remove();
+ }
+ }
+ }
+
+ if (sessionMap.size() == 0) {
+ sessionsInThread.remove();
+ }
+
+ }
+ }
+
+ private Session getSessionFromThreadLocal(Serializable sessionId) {
+ if (sessionsInThread.get() == null) {
+ return null;
+ } else {
+ Map<Serializable, SessionInMemory> sessionMap = (Map) sessionsInThread.get();
+ SessionInMemory sessionInMemory = (SessionInMemory) sessionMap.get(sessionId);
+ if (sessionInMemory == null) {
+ return null;
+ } else {
+ logger.debug("read session from memory");
+ return sessionInMemory.getSession();
+ }
+ }
+ }
+
+ private long getSessionInMemoryLiveTime(SessionInMemory sessionInMemory) {
+ Date now = new Date();
+ return now.getTime() - sessionInMemory.getCreateTime().getTime();
+ }
+
+ private String getRedisSessionKey(Serializable sessionId) {
+ return this.keyPrefix + sessionId;
+ }
+
+ @Override
+ public IRedisManager getRedisManager() {
+ return this.redisManager;
+ }
+
+ public void setRedisManager(MyRedisManager redisManager) {
+ this.redisManager = redisManager;
+ }
+
+ @Override
+ public String getKeyPrefix() {
+ return this.keyPrefix;
+ }
+
+ @Override
+ public void setKeyPrefix(String keyPrefix) {
+ this.keyPrefix = keyPrefix;
+ }
+
+
+ @Override
+ public long getSessionInMemoryTimeout() {
+ return this.sessionInMemoryTimeout;
+ }
+
+ @Override
+ public void setSessionInMemoryTimeout(long sessionInMemoryTimeout) {
+ this.sessionInMemoryTimeout = sessionInMemoryTimeout;
+ }
+
+ @Override
+ public int getExpire() {
+ return this.expire;
+ }
+
+ @Override
+ public void setExpire(int expire) {
+ this.expire = expire;
+ }
+
+ @Override
+ public boolean getSessionInMemoryEnabled() {
+ return this.sessionInMemoryEnabled;
+ }
+
+ @Override
+ public void setSessionInMemoryEnabled(boolean sessionInMemoryEnabled) {
+ this.sessionInMemoryEnabled = sessionInMemoryEnabled;
+ }
+
+ public static ThreadLocal getSessionsInThread() {
+ return sessionsInThread;
+ }
+}