🛡️ 只需一行配置,搞定多端登录、单端登录、互斥登录、七天免登录|Java 登录认证全攻略

119 阅读3分钟

🛡️ 只需一行配置,搞定多端登录、单端登录、互斥登录、七天免登录|Java 登录认证全攻略

作为一名写了 8 年 Java 的后端开发者,我最怕听到产品说:“我们登录要支持多端登录、单端登录、同端互斥登录、PC 和移动端互不影响、七天免登录……能不能搞一下?”

其实,这些登录策略本质上就是 Token 管理策略 + 会话控制。只要设计好认证框架,切换登录策略只需一行配置

今天这篇文章,我就来手把手教你:

  • 各种登录策略的区别
  • 如何优雅地实现它们
  • 如何通过配置快速切换策略
  • 附核心代码实现(高可读 + 注释齐)

🌍 登录策略全景图

策略名描述
多端登录任意设备均可登录,互不影响
单端登录每次登录都会踢掉上一个设备
同端互斥登录同一种设备只能登录一个(移动端互踢,PC 和移动端彼此不影响)
七天免登录登录后 7 天内无需再次登录,使用刷新 Token

🧠 本质理解:登录策略 = Token + Session 管控策略

几乎所有登录策略的区别都在于:

  1. Token 的生成与存储
  2. 登录时旧 Token 的处理方式
  3. 是否启用刷新 Token(七天免登录)

🛠️ 核心设计思路

我们以 JWT + Redis 为基础实现登录认证系统,核心设计如下:

🔑 Token 结构设计(支持多端和互斥)

public class LoginToken {
    private String userId;       // 用户ID
    private String deviceType;   // 设备类型 PC / MOBILE / PAD
    private String token;        // JWT字符串
    private long expireAt;       // 过期时间
}

Redis 存储结构设计:

// 一个用户在不同设备上的登录状态维护
LOGIN:${userId}:${deviceType} -> token

🧬 登录策略配置

public enum LoginPolicy {
    MULTI,         // 多端登录
    SINGLE_GLOBAL, // 单点登录(全端互斥)
    SINGLE_DEVICE, // 同端互斥登录(PC/Mobile 分端互斥)
}

配置中心(application.yml 或数据库配置)

auth:
  login-policy: SINGLE_DEVICE
  token-expire-seconds: 3600
  refresh-token-expire-seconds: 604800  # 7天

🧩 登录流程核心代码实现

@Service
public class AuthService {

    @Value("${auth.login-policy}")
    private LoginPolicy loginPolicy;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    public String login(String userId, String deviceType) {
        String token = JwtUtil.generateToken(userId, deviceType);

        // 生成 Redis Key
        String redisKey = "LOGIN:" + userId + ":" + deviceType;

        switch (loginPolicy) {
            case SINGLE_GLOBAL:
                // 清除所有设备的登录
                cleanAllDeviceSessions(userId);
                break;
            case SINGLE_DEVICE:
                // 清除当前设备上的旧Token
                redisTemplate.delete(redisKey);
                break;
            case MULTI:
                // 不清除任何设备
                break;
        }

        // 保存新Token
        redisTemplate.opsForValue().set(redisKey, token, Duration.ofHours(1));

        return token;
    }

    private void cleanAllDeviceSessions(String userId) {
        Set<String> keys = redisTemplate.keys("LOGIN:" + userId + ":*");
        if (keys != null && !keys.isEmpty()) {
            redisTemplate.delete(keys);
        }
    }
}

🔄 七天免登录机制(刷新Token)

✅ 登录时返回两个 Token:

  • accessToken:有效期短(如1小时)
  • refreshToken:有效期长(如7天)

✅ 当 accessToken 过期,客户端自动用 refreshToken 换新 Token

@PostMapping("/auth/refresh")
public ResponseEntity<?> refreshToken(@RequestBody RefreshRequest request) {
    String refreshToken = request.getRefreshToken();

    if (!JwtUtil.isValid(refreshToken)) {
        return ResponseEntity.status(401).body("Refresh Token失效");
    }

    String userId = JwtUtil.getUserId(refreshToken);
    String deviceType = JwtUtil.getDeviceType(refreshToken);

    // 校验是否还在 Redis 中
    String redisKey = "LOGIN:" + userId + ":" + deviceType;
    String currentToken = redisTemplate.opsForValue().get(redisKey);
    if (currentToken == null || !currentToken.equals(refreshToken)) {
        return ResponseEntity.status(401).body("会话已过期");
    }

    // 生成新 accessToken
    String newAccessToken = JwtUtil.generateAccessToken(userId, deviceType);

    return ResponseEntity.ok(newAccessToken);
}

🔄 切换策略?只需改配置!

auth:
  login-policy: SINGLE_GLOBAL

无需改代码,策略立即生效,优雅切换,安全高效


✅ 总结:登录系统也能模块化配置

能力实现方式
多端登录不清除旧 Token
单端登录清除所有设备旧 Token
同端互斥登录只清当前设备类型
七天免登录access + refreshToken 双 Token 模式

📌 最后

这套方案已经在多个中大型项目中稳定运行,包括 SaaS 平台、管理后台、移动端 API 等。它的核心优势在于:

  • 开箱即用,策略可配置
  • 支持 JWT + Redis,轻量高效
  • 逻辑清晰,安全可控

如果你也正好在做登录认证模块,不妨参考这套思路,让你的登录策略“可插拔” ,轻松应对各种产品需求!


作者:一个写了 8 年后端的 Java 工程师,持续关注架构落地、认证安全与系统稳定性。