trading-order-admin/src/main/java/com/yami/trading/admin/controller/AdminLoginController.java
@@ -122,12 +122,18 @@ userInfoInToken.setPerms(getUserPermissions(sysUser.getUserId())); userInfoInToken.setNickName(sysUser.getUsername()); userInfoInToken.setShopId(sysUser.getShopId()); tokenStore.deleteAllToken(String.valueOf(SysTypeEnum.ADMIN.value()), String.valueOf(sysUser.getUserId())); //tokenStore.deleteAllToken(String.valueOf(SysTypeEnum.ADMIN.value()), String.valueOf(sysUser.getUserId())); // 存储token返回vo TokenInfoVO tokenInfoVO = tokenStore.storeAndGetVo(userInfoInToken); RedisUtil.set(RedisKeys.ACCESS_IP + sysUser.getUserId().intValue(),IPHelper.getIpAddr()); //RedisUtil.set(RedisKeys.ACCESS_IP + sysUser.getUserId().intValue(),IPHelper.getIpAddr()); // 关键修改2:用Redis Set存储多个登录IP(自动去重) String loginIp = IPHelper.getIpAddr(); String ipSetKey = RedisKeys.ACCESS_IP + sysUser.getUserId().intValue(); // 键:ACCESS_IP+用户ID long tokenExpiresIn = tokenInfoVO.getExpiresIn(); // 与Token过期时间一致 RedisUtil.sAdd(ipSetKey, loginIp); // 存入IP到Set RedisUtil.expire(ipSetKey, tokenExpiresIn); // 设置过期时间 String context = MessageFormat.format("ip:{0}, 登录系统,时间[{1}]", new Object[]{IPHelper.getIpAddr(), DateUtils.dateToStr(new Date(), trading-order-common/src/main/java/com/yami/trading/common/constants/RedisKeys.java
@@ -2,7 +2,7 @@ public class RedisKeys { public final static String ACCESS_IP = "ACCESS_IP"; public final static String ACCESS_IP = "NEW_ACCESS_IP"; /** * item杠杆倍数 trading-order-common/src/main/java/com/yami/trading/common/util/RedisUtil.java
@@ -7,11 +7,9 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** * @author lh @@ -263,4 +261,19 @@ return retList; } // 向Set中添加元素(用于存储登录IP) public static Long sAdd(String key, String value) { return redisTemplate.opsForSet().add(key, value); } // 获取Set中的所有元素(用于获取已授权IP列表)- 兼容Java 8 public static Set<String> sMembers(String key) { Set<Object> objectSet = redisTemplate.opsForSet().members(key); if (CollectionUtil.isEmpty(objectSet)) { // 替换 Set.of() 为 new HashSet<>()(Java 8支持) return new HashSet<>(); } // 转换为String类型Set return objectSet.stream().map(String::valueOf).collect(Collectors.toSet()); } } trading-order-security-common/src/main/java/com/yami/trading/security/common/bo/UserInfoInTokenBO.java
@@ -12,6 +12,7 @@ import com.yami.trading.security.common.enums.SysTypeEnum; import lombok.Data; import java.io.Serializable; import java.util.Set; /** @@ -21,7 +22,8 @@ * @date 2022/3/25 17:33 */ @Data public class UserInfoInTokenBO { public class UserInfoInTokenBO implements Serializable { // 新增:实现Serializable接口 private static final long serialVersionUID = 1L; /** * 用户在自己系统的用户id @@ -66,4 +68,7 @@ */ private Long otherId; // 新增:无参构造函数(Jackson序列化必须,Lombok @Data不默认生成) public UserInfoInTokenBO() {} } trading-order-security-common/src/main/java/com/yami/trading/security/common/filter/AuthFilter.java
@@ -3,10 +3,7 @@ import java.io.IOException; import java.net.URLDecoder; import java.time.ZoneId; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.Filter; @@ -203,10 +200,15 @@ // 如果有 token,并且解析成功,则走以下处理逻辑 if (userInfoInToken.getSysType().intValue() == SysTypeEnum.ADMIN.value().intValue()) { if (!pathMatcher.match("/updateCheckIp", requestUri)) { Object loginIP = RedisUtil.get(RedisKeys.ACCESS_IP + userInfoInToken.getUserId()); if (null != loginIP && !IPHelper.equalIpSegment(loginIP.toString(), clientIp)) { logger.error("The Login IP Is Inconsistent With The Operation IP! Login-IP:{} Access-IP:{} Servlet-Path:{}", loginIP, clientIp, servletPath); httpHandler.printServerResponseToWeb("", 1001); String ipSetKey = RedisKeys.ACCESS_IP + userInfoInToken.getUserId(); // 从Redis Set中获取该用户所有已授权登录IP Set<String> authorizedIpSet = RedisUtil.sMembers(ipSetKey); // 校验逻辑:已授权IP列表不为空,且当前IP在列表中 if (CollectionUtil.isEmpty(authorizedIpSet) || !authorizedIpSet.contains(clientIp)) { logger.error("The Operation IP Is Not Authorized! Authorized-IPs:{}, Access-IP:{}, Servlet-Path:{}", authorizedIpSet, clientIp, servletPath); httpHandler.printServerResponseToWeb("当前IP未授权,请使用已登录设备访问或重新登录", 1001); return; } }