132 lines
4.1 KiB
Java
132 lines
4.1 KiB
Java
package com.test.bijihoudaun.util;
|
||
|
||
import java.time.LocalDateTime;
|
||
import java.time.temporal.ChronoUnit;
|
||
import java.util.concurrent.ConcurrentHashMap;
|
||
|
||
/**
|
||
* 登录锁定工具类
|
||
* 使用本地内存存储登录失败记录
|
||
*/
|
||
public class LoginLockUtil {
|
||
|
||
// 最大失败次数
|
||
private static final int MAX_FAILED_ATTEMPTS = 5;
|
||
// 锁定时间(分钟)
|
||
private static final int LOCK_TIME_MINUTES = 30;
|
||
// 失败记录过期时间(分钟)
|
||
private static final int RECORD_EXPIRE_MINUTES = 60;
|
||
|
||
// 登录失败记录:key=用户名,value=失败记录
|
||
private static final ConcurrentHashMap<String, LoginAttempt> attempts = new ConcurrentHashMap<>();
|
||
|
||
private static class LoginAttempt {
|
||
int failedCount;
|
||
LocalDateTime lastAttemptTime;
|
||
LocalDateTime lockUntil;
|
||
|
||
LoginAttempt() {
|
||
this.failedCount = 0;
|
||
this.lastAttemptTime = LocalDateTime.now();
|
||
this.lockUntil = null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 记录登录失败
|
||
* @param username 用户名
|
||
*/
|
||
public static void recordFailedAttempt(String username) {
|
||
if (username == null || username.isEmpty()) return;
|
||
|
||
cleanupExpiredRecords();
|
||
|
||
LoginAttempt attempt = attempts.computeIfAbsent(username, k -> new LoginAttempt());
|
||
attempt.failedCount++;
|
||
attempt.lastAttemptTime = LocalDateTime.now();
|
||
|
||
// 达到最大失败次数,锁定账号
|
||
if (attempt.failedCount >= MAX_FAILED_ATTEMPTS) {
|
||
attempt.lockUntil = LocalDateTime.now().plusMinutes(LOCK_TIME_MINUTES);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 记录登录成功(清除失败记录)
|
||
* @param username 用户名
|
||
*/
|
||
public static void recordSuccess(String username) {
|
||
if (username == null || username.isEmpty()) return;
|
||
attempts.remove(username);
|
||
}
|
||
|
||
/**
|
||
* 检查账号是否被锁定
|
||
* @param username 用户名
|
||
* @return true-已锁定,false-未锁定
|
||
*/
|
||
public static boolean isLocked(String username) {
|
||
if (username == null || username.isEmpty()) return false;
|
||
|
||
LoginAttempt attempt = attempts.get(username);
|
||
if (attempt == null) return false;
|
||
|
||
// 检查是否仍在锁定时间内
|
||
if (attempt.lockUntil != null) {
|
||
if (LocalDateTime.now().isBefore(attempt.lockUntil)) {
|
||
return true;
|
||
} else {
|
||
// 锁定时间已过,清除记录
|
||
attempts.remove(username);
|
||
return false;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 获取剩余锁定时间(秒)
|
||
* @param username 用户名
|
||
* @return 剩余秒数,如果未锁定返回0
|
||
*/
|
||
public static long getRemainingLockTime(String username) {
|
||
if (username == null || username.isEmpty()) return 0;
|
||
|
||
LoginAttempt attempt = attempts.get(username);
|
||
if (attempt == null || attempt.lockUntil == null) return 0;
|
||
|
||
long remaining = ChronoUnit.SECONDS.between(LocalDateTime.now(), attempt.lockUntil);
|
||
return Math.max(0, remaining);
|
||
}
|
||
|
||
/**
|
||
* 获取剩余失败次数
|
||
* @param username 用户名
|
||
* @return 剩余次数
|
||
*/
|
||
public static int getRemainingAttempts(String username) {
|
||
if (username == null || username.isEmpty()) return MAX_FAILED_ATTEMPTS;
|
||
|
||
LoginAttempt attempt = attempts.get(username);
|
||
if (attempt == null) return MAX_FAILED_ATTEMPTS;
|
||
|
||
return Math.max(0, MAX_FAILED_ATTEMPTS - attempt.failedCount);
|
||
}
|
||
|
||
/**
|
||
* 清理过期记录
|
||
*/
|
||
private static void cleanupExpiredRecords() {
|
||
LocalDateTime now = LocalDateTime.now();
|
||
attempts.entrySet().removeIf(entry -> {
|
||
LoginAttempt attempt = entry.getValue();
|
||
// 未锁定且长时间没有登录的记录
|
||
if (attempt.lockUntil == null) {
|
||
return ChronoUnit.MINUTES.between(attempt.lastAttemptTime, now) > RECORD_EXPIRE_MINUTES;
|
||
}
|
||
// 锁定已过期的记录
|
||
return now.isAfter(attempt.lockUntil);
|
||
});
|
||
}
|
||
}
|