diff --git a/virtual-patient-common/pom.xml b/virtual-patient-common/pom.xml
index f666a501..39517bdf 100644
--- a/virtual-patient-common/pom.xml
+++ b/virtual-patient-common/pom.xml
@@ -30,6 +30,15 @@
             </exclusions>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+        </dependency>
+
             <!-- 其他依赖 -->
         <dependency>
             <groupId>org.springframework.boot</groupId>
diff --git a/virtual-patient-common/src/main/java/com/supervision/config/JwtInterceptor.java b/virtual-patient-common/src/main/java/com/supervision/config/JwtInterceptor.java
index cd4374d1..8513504d 100644
--- a/virtual-patient-common/src/main/java/com/supervision/config/JwtInterceptor.java
+++ b/virtual-patient-common/src/main/java/com/supervision/config/JwtInterceptor.java
@@ -1,13 +1,17 @@
 package com.supervision.config;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import cn.hutool.jwt.JWT;
 import cn.hutool.jwt.JWTUtil;
+import com.supervision.constant.UserTokenConstant;
 import com.supervision.exception.BusinessException;
+import com.supervision.util.SpringBeanUtil;
 import com.supervision.util.TokenUtil;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.http.HttpStatus;
 import org.springframework.lang.Nullable;
 import org.springframework.web.servlet.HandlerInterceptor;
@@ -19,10 +23,16 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 
 @Slf4j
 public class JwtInterceptor implements HandlerInterceptor {
 
+    private final RedisTemplate<String, String> redisTemplate;
+
+    public JwtInterceptor(RedisTemplate<String, String> redisTemplate) {
+        this.redisTemplate = redisTemplate;
+    }
 
 
     @Override
@@ -43,11 +53,33 @@ public class JwtInterceptor implements HandlerInterceptor {
         // 校验token是否过期,如果过期了,需要提示过期重新登录
         checkTokenExpire(jwt);
         // 校验是否重复登录
-        //UserSingleLoginConfig.checkSingleLogin(jwt);
+        //checkSingleLogin(jwt);
         cacheAuth(jwt);
         return true;
     }
 
+    public void checkSingleLogin(String userId, JWT currentJwt) {
+
+        if (Boolean.FALSE.equals(redisTemplate.hasKey(UserTokenConstant.TOKEN_CACHE + userId))) {
+            throw new BusinessException("用户已被踢下线或超时,请重新登录", 505);
+        }
+        String value = redisTemplate.opsForValue().get(UserTokenConstant.TOKEN_CACHE + userId);
+
+        long redisCacheTime = Long.parseLong(String.valueOf(value));
+        Object currentJwtIssueTimeObject = currentJwt.getPayload("issueTime");
+        long currentJwtIssueTime = Long.parseLong(String.valueOf(currentJwtIssueTimeObject));
+        if (redisCacheTime == currentJwtIssueTime) {
+            // 如果相等,说明这个token就是最新的,直接放行
+            return;
+        } else if (currentJwtIssueTime > redisCacheTime) {
+            // 如果当前请求时间,大于Redis缓存时间,说明重新登录了,这个时候要把最新的放到缓存中
+            redisTemplate.opsForValue().set(UserTokenConstant.TOKEN_CACHE + userId, String.valueOf(System.currentTimeMillis()), 1000 * 5L, TimeUnit.MILLISECONDS);
+        } else {
+            // 走到这里,说明redisCacheTime是最新的,说明当前用户请求了一个新的token,那么原来的用户就踢掉
+            throw new BusinessException("当前用户已在其他地方登录!", 505);
+        }
+    }
+
     @Override
     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                 @Nullable Exception ex) throws Exception {
@@ -68,7 +100,6 @@ public class JwtInterceptor implements HandlerInterceptor {
     }
 
 
-
     private void cacheAuth(JWT jwt) {
         try {
             JSONObject claimsJson = jwt.getPayload().getClaimsJson();
diff --git a/virtual-patient-common/src/main/java/com/supervision/config/UserSingleLoginConfig.java b/virtual-patient-common/src/main/java/com/supervision/config/UserSingleLoginConfig.java
deleted file mode 100644
index c3f0f837..00000000
--- a/virtual-patient-common/src/main/java/com/supervision/config/UserSingleLoginConfig.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.supervision.config;
-
-import cn.hutool.cache.CacheUtil;
-import cn.hutool.cache.impl.TimedCache;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.jwt.JWT;
-import com.supervision.exception.BusinessException;
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-public class UserSingleLoginConfig {
-
-    /**
-     * 创建缓存,过期时间为5分钟,如果5分钟内没有请求过来,就认为是超时
-     */
-    private static final TimedCache<Object, JWT> singleLoginTokenCacheMap = CacheUtil.newTimedCache(1000 * 5 * 24);
-
-    static {
-        // 每秒钟扫描一次
-        singleLoginTokenCacheMap.schedulePrune(1000);
-    }
-
-
-    public static void loginOrRefreshUser(String id, JWT jwt) {
-        singleLoginTokenCacheMap.put(id, jwt);
-    }
-
-    public static void checkSingleLogin(JWT currentJwt) {
-        Object id = currentJwt.getPayload("id");
-        JWT singleLoginTokenCache = singleLoginTokenCacheMap.get(id);
-        if (ObjectUtil.isEmpty(singleLoginTokenCache)) {
-            throw new BusinessException("用户已被踢下线或超时,请重新登录", 505);
-        }
-        // 然后将当前的expireTime和singleLoginTokenCache进行比较
-        Object expireTime = singleLoginTokenCache.getPayload("expireTime");
-        long singleLoginTokenCacheExpireTime = Long.parseLong(String.valueOf(expireTime));
-        Object currentJwtExpireTimeObject = currentJwt.getPayload("expireTime");
-        long currentJwtExpireTime = Long.parseLong(String.valueOf(currentJwtExpireTimeObject));
-        if (singleLoginTokenCacheExpireTime == currentJwtExpireTime) {
-            // 如果相等,说明这个token就是最新的,直接放行
-            return;
-        } else if (currentJwtExpireTime > singleLoginTokenCacheExpireTime) {
-            // 如果当前的超时时间要大于缓存的,说明重新登录了,这个时候要把最新的放到缓存中
-            singleLoginTokenCacheMap.put(id, currentJwt);
-        } else {
-            // 走到这里,说明singleLoginTokenCache是最新的,说明当前用户请求了一个新的token,那么原来的用户就踢掉
-            throw new BusinessException("当前用户已在其他地方登录!", 505);
-        }
-    }
-}
diff --git a/virtual-patient-common/src/main/java/com/supervision/config/WebConfig.java b/virtual-patient-common/src/main/java/com/supervision/config/WebConfig.java
index a468d508..80e72538 100644
--- a/virtual-patient-common/src/main/java/com/supervision/config/WebConfig.java
+++ b/virtual-patient-common/src/main/java/com/supervision/config/WebConfig.java
@@ -5,8 +5,10 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
@@ -18,10 +20,13 @@ import java.util.List;
 @Configuration
 public class WebConfig implements WebMvcConfigurer {
 
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
         // 添加权限拦截器
-        registry.addInterceptor(new JwtInterceptor())
+        registry.addInterceptor(new JwtInterceptor(redisTemplate))
                 .addPathPatterns("/**")
                 .excludePathPatterns(ignorePathPatterns());
     }
diff --git a/virtual-patient-common/src/main/java/com/supervision/constant/UserTokenConstant.java b/virtual-patient-common/src/main/java/com/supervision/constant/UserTokenConstant.java
new file mode 100644
index 00000000..a6e5d2fb
--- /dev/null
+++ b/virtual-patient-common/src/main/java/com/supervision/constant/UserTokenConstant.java
@@ -0,0 +1,6 @@
+package com.supervision.constant;
+
+public interface UserTokenConstant {
+
+    String TOKEN_CACHE = "USER:LOGIN:TOKEN:";
+}
diff --git a/virtual-patient-common/src/main/java/com/supervision/util/TokenUtil.java b/virtual-patient-common/src/main/java/com/supervision/util/TokenUtil.java
index b33841ca..1a0b0bf0 100644
--- a/virtual-patient-common/src/main/java/com/supervision/util/TokenUtil.java
+++ b/virtual-patient-common/src/main/java/com/supervision/util/TokenUtil.java
@@ -13,6 +13,7 @@ public class TokenUtil {
         JSONObject info = JSONUtil.parseObj(userInfo);
         // 过期时间一天,同时这个字段也作为单点登录使用
         info.putOnce("expireTime",System.currentTimeMillis() + 1000 * 60 * 60 * 24);
+        info.putOnce("issueTime",System.currentTimeMillis());
         return JWTUtil.createToken(info, signer);
     }
 }
diff --git a/virtual-patient-manage/src/main/resources/application-dev.yml b/virtual-patient-manage/src/main/resources/application-dev.yml
index c697021a..a6ba84a7 100644
--- a/virtual-patient-manage/src/main/resources/application-dev.yml
+++ b/virtual-patient-manage/src/main/resources/application-dev.yml
@@ -46,6 +46,10 @@ spring:
           log-slow-sql: true                                # 是否开启 慢SQL 记录,默认false
           slow-sql-millis: 5000                             # 慢 SQL 的标准,默认 3000,单位:毫秒
           merge-sql: false                                  # 合并多个连接池的监控数据,默认false
+  redis:
+    host: 192.168.10.138
+    port: 6379
+    password: 123456
 
 mybatis-plus:
   mapper-locations: classpath*:mapper/**/*.xml
diff --git a/virtual-patient-manage/src/main/resources/application-prod.yml b/virtual-patient-manage/src/main/resources/application-prod.yml
index d09b3af7..cd7989fa 100644
--- a/virtual-patient-manage/src/main/resources/application-prod.yml
+++ b/virtual-patient-manage/src/main/resources/application-prod.yml
@@ -47,6 +47,10 @@ spring:
           log-slow-sql: true                                # 是否开启 慢SQL 记录,默认false
           slow-sql-millis: 5000                             # 慢 SQL 的标准,默认 3000,单位:毫秒
           merge-sql: false                                  # 合并多个连接池的监控数据,默认false
+  redis:
+    host: 192.168.10.138
+    port: 6379
+    password: 123456
 
 mybatis-plus:
   mapper-locations: classpath*:mapper/**/*.xml
diff --git a/virtual-patient-manage/src/main/resources/application-test.yml b/virtual-patient-manage/src/main/resources/application-test.yml
index a7a01804..f9335324 100644
--- a/virtual-patient-manage/src/main/resources/application-test.yml
+++ b/virtual-patient-manage/src/main/resources/application-test.yml
@@ -47,6 +47,10 @@ spring:
           log-slow-sql: true                                # 是否开启 慢SQL 记录,默认false
           slow-sql-millis: 5000                             # 慢 SQL 的标准,默认 3000,单位:毫秒
           merge-sql: false                                  # 合并多个连接池的监控数据,默认false
+  redis:
+    host: 192.168.10.138
+    port: 6379
+    password: 123456
 
 mybatis-plus:
   mapper-locations: classpath*:mapper/**/*.xml
diff --git a/virtual-patient-web/src/main/java/com/supervision/controller/UserController.java b/virtual-patient-web/src/main/java/com/supervision/controller/UserController.java
index a1a11e6a..3eb554a4 100644
--- a/virtual-patient-web/src/main/java/com/supervision/controller/UserController.java
+++ b/virtual-patient-web/src/main/java/com/supervision/controller/UserController.java
@@ -2,9 +2,7 @@ package com.supervision.controller;
 
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
-import cn.hutool.jwt.JWT;
-import com.supervision.config.UserSingleLoginConfig;
-import com.supervision.domain.UserInfo;
+import com.supervision.constant.UserTokenConstant;
 import com.supervision.exception.BusinessException;
 import com.supervision.model.User;
 import com.supervision.pojo.vo.LoginReqVO;
@@ -14,9 +12,11 @@ import com.supervision.util.UserUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.Optional;
+import java.util.concurrent.TimeUnit;
 
 @Api(tags = "用户管理")
 @RestController
@@ -26,6 +26,9 @@ public class UserController {
 
     private final UserService userService;
 
+    private final RedisTemplate<String, String> redisTemplate;
+
+
     @ApiOperation("登录")
     @PostMapping("login")
     public String login(@RequestBody LoginReqVO reqVO) {
@@ -40,16 +43,17 @@ public class UserController {
             throw new BusinessException("密码错误");
         }
         String token = TokenUtil.creatToken(JSONUtil.toJsonStr(user.get()));
-        // 将用户的token保存起来
-        UserSingleLoginConfig.loginOrRefreshUser(user.get().getId(), JWT.create().parse(token));
+        // 将用户的token保存起来,超时时间为5分钟
+        redisTemplate.opsForValue().set(UserTokenConstant.TOKEN_CACHE + user.get().getId(), String.valueOf(System.currentTimeMillis()), 1000 * 5L, TimeUnit.MILLISECONDS);
         return token;
     }
 
     @ApiOperation("token心跳")
     @PostMapping("keepaliveToken")
     public void keepaliveToken() {
-        String token = UserUtil.getUserToken();
-        UserSingleLoginConfig.loginOrRefreshUser(UserUtil.getUser().getId(), JWT.create().parse(token));
+        User user = UserUtil.getUser();
+        // 每次心跳都设置为5分钟之后
+        redisTemplate.expire(UserTokenConstant.TOKEN_CACHE + user.getId(), 1000 * 5L, TimeUnit.MILLISECONDS);
     }
 
 
diff --git a/virtual-patient-web/src/main/resources/application-dev.yml b/virtual-patient-web/src/main/resources/application-dev.yml
index 0750ca75..3778db98 100644
--- a/virtual-patient-web/src/main/resources/application-dev.yml
+++ b/virtual-patient-web/src/main/resources/application-dev.yml
@@ -46,6 +46,11 @@ spring:
           log-slow-sql: true                                # 是否开启 慢SQL 记录,默认false
           slow-sql-millis: 5000                             # 慢 SQL 的标准,默认 3000,单位:毫秒
           merge-sql: false                                  # 合并多个连接池的监控数据,默认false
+  redis:
+    host: 192.168.10.138
+    port: 6379
+    password: 123456
+
 
 mybatis-plus:
   mapper-locations: classpath*:mapper/**/*.xml
diff --git a/virtual-patient-web/src/main/resources/application-prod.yml b/virtual-patient-web/src/main/resources/application-prod.yml
index 84d6c7b9..06592d11 100644
--- a/virtual-patient-web/src/main/resources/application-prod.yml
+++ b/virtual-patient-web/src/main/resources/application-prod.yml
@@ -47,6 +47,10 @@ spring:
           log-slow-sql: true                                # 是否开启 慢SQL 记录,默认false
           slow-sql-millis: 5000                             # 慢 SQL 的标准,默认 3000,单位:毫秒
           merge-sql: false                                  # 合并多个连接池的监控数据,默认false
+  redis:
+    host: 192.168.10.138
+    port: 6379
+    password: 123456
 
 mybatis-plus:
   mapper-locations: classpath*:mapper/**/*.xml
diff --git a/virtual-patient-web/src/main/resources/application-test.yml b/virtual-patient-web/src/main/resources/application-test.yml
index 2632bb2a..45c38e68 100644
--- a/virtual-patient-web/src/main/resources/application-test.yml
+++ b/virtual-patient-web/src/main/resources/application-test.yml
@@ -47,6 +47,10 @@ spring:
           log-slow-sql: true                                # 是否开启 慢SQL 记录,默认false
           slow-sql-millis: 5000                             # 慢 SQL 的标准,默认 3000,单位:毫秒
           merge-sql: false                                  # 合并多个连接池的监控数据,默认false
+  redis:
+    host: 192.168.10.138
+    port: 6379
+    password: 123456
 
 mybatis-plus:
   mapper-locations: classpath*:mapper/**/*.xml