zyy
2025-11-20 4e5138fdfd60edf0d67787582905dfcc0801d667
多ip地址登录
5 files modified
60 ■■■■ changed files
trading-order-admin/src/main/java/com/yami/trading/admin/controller/AdminLoginController.java 12 ●●●● patch | view | raw | blame | history
trading-order-common/src/main/java/com/yami/trading/common/constants/RedisKeys.java 2 ●●● patch | view | raw | blame | history
trading-order-common/src/main/java/com/yami/trading/common/util/RedisUtil.java 21 ●●●● patch | view | raw | blame | history
trading-order-security-common/src/main/java/com/yami/trading/security/common/bo/UserInfoInTokenBO.java 7 ●●●● patch | view | raw | blame | history
trading-order-security-common/src/main/java/com/yami/trading/security/common/filter/AuthFilter.java 18 ●●●●● patch | view | raw | blame | history
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;
                        }
                    }