近期碰到一个问题,在某个系统测试过程中,频繁快速请求用户登录接口,造成致服务器负载增加,另外在攻防演练时,为防止暴力破解密码和自动化攻击,完善用户操作日志和加强安全提醒,决定在用户登录过程添加限制条件和用户登录错误锁定规则,我们利用Redis来做用户登录记录缓存和用户锁定,下面简单介绍一下实现过程。
一、添加依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
二、编写Redis连接工具类
import redis.clients.jedis.Jedis;
public class RedisUtil {
private static final String REDIS_HOST = "localhost";
private static final int REDIS_PORT = 6379;
public static Jedis getRedisConnection() {
return new Jedis(REDIS_HOST, REDIS_PORT);
}
}
三、登录流程代码
import redis.clients.jedis.Jedis;
public class LoginService {
private static final String LOGIN_ATTEMPTS_KEY_PREFIX = "login:attempts:";
private static final int MAX_ATTEMPTS = 5;
private static final long LOCK_DURATION = 10 * 60; // 锁定时间,单位秒
public boolean attemptLogin(String username, String password) {
Jedis jedis = null;
try {
jedis = RedisUtil.getRedisConnection();
String key = LOGIN_ATTEMPTS_KEY_PREFIX + username;
// 检查用户是否已被锁定
if (isLocked(jedis, key)) {
return false; // 用户已被锁定
}
// 模拟密码验证(实际开发中应从数据库验证)
boolean isAuthenticated = "your_password_hash".equals(password); // 假设的密码验证
if (!isAuthenticated) {
// 登录失败,增加尝试次数
int attempts = jedis.incr(key);
if (attempts >= MAX_ATTEMPTS) {
// 达到最大尝试次数,锁定用户
jedis.expire(key, LOCK_DURATION); // 设置锁定时间
return false; // 返回登录失败并提示用户账号被锁定
}
return false; // 返回登录失败
}
// 登录成功,重置尝试次数
jedis.del(key);
return true;
} finally {
if (jedis != null) {
jedis.close();
}
}
}
private boolean isLocked(Jedis jedis, String key) {
Long ttl = jedis.ttl(key);
return ttl != -1 && ttl > 0;
}
}
四、其他说明
以上代码示例只展示实现原理,具体到项目中,应注意以下几点:
- 在实际开发中,密码验证应该通过查询数据库中的用户信息来进行,而不是像示例中那样硬编码。
- 考虑到Redis的持久化和备份策略,确保在Redis服务器故障或重启后,登录尝试次数和锁定状态能够恢复。
- 考虑到Redis的性能和内存限制,可能需要设置合理的键过期策略,以避免不必要的内存占用。
- 可以在Redis中使用哈希表(hashes)来存储更复杂的用户登录信息,例如登录IP、登录时间等,以便进行更细致的安全审计和日志记录。
- 为了提高系统安全性,建议对Redis服务器进行适当的安全配置,如设置密码、限制访问IP等。