随着互联网的快速发展,用户登录系统的安全性越来越受到重视。为了提高用户体验和系统安全性,我们通常会采用缓存技术来优化登录流程。Redis作为一种高性能的内存数据库,广泛应用于各种需要快速读写数据的场景。本文将结合实际代码,探讨Redis在用户登录系统中的应用,以及如何存储登录日志。
在用户登录过程中,为了防止恶意攻击,我们通常会设置账号锁定机制。当用户连续多次输入错误密码时,系统会暂时锁定该账号,禁止其继续尝试登录。
在上述代码中,我们使用Redis来实现这一功能。具体实现如下:
USER:LOCK:username
。USER:ERROR:username
。当用户输入错误密码时,我们会检查Redis中是否存在对应的lockKey
。如果存在且锁定时间未过,则返回账号已被锁定的提示信息;如果锁定时间已过,则删除lockKey
以解锁账号。
if (resdisUtil.hasKey(lockKey)) {
long lockTime = (long) resdisUtil.get(lockKey);
if (System.currentTimeMillis() - lockTime < 600 * 1000) { // 10分钟
long remainingTime = (600 * 1000 - (System.currentTimeMillis() - lockTime)) / 1000;
loginLog.setLoginStatus("0");
loginLog.setMessage("账号已被锁定10分钟");
loginLogService.save(loginLog, request);
return error("账号已被锁定,请" + remainingTime + "秒后重试");
} else {
resdisUtil.del(lockKey); // 锁定时间已过,解锁账号
}
}
为了判断是否需要锁定账号,我们需要统计用户输入错误密码的次数。每次用户输入错误密码时,我们会在Redis中对应的errorKey
上自增1。
Long errorCount = resdisUtil.incr(errorKey, 1);
if (errorCount != null && errorCount >= 5) {
resdisUtil.set(lockKey, System.currentTimeMillis(), 600);
resdisUtil.del(errorKey); // 错误次数达到上限,锁定账号
loginLog.setLoginStatus("0");
loginLog.setMessage("账号已被锁定10分钟");
loginLogService.save(loginLog, request);
return error("账号已被锁定,请10分钟后重试");
} else {
loginLog.setLoginStatus("0");
loginLog.setMessage("密码输入错误" + errorCount + "次");
loginLogService.save(loginLog, request);
return error("密码输入错误");
}
当用户成功登录后,我们需要清除对应的errorKey
,以避免因之前的错误登录记录导致账号被误锁定。
if (match) {
userInfo.setRole(roleService.getById(userInfo.getRoleId()));
userInfo.setDept(deptService.getById(userInfo.getDeptId()));
userInfo.setPost(postService.getById(userInfo.getPostId()));
loginLog.setLoginStatus("1");
loginLog.setMessage("登录成功");
loginLogService.save(loginLog, request);
resdisUtil.del(errorKey); // 密码正确,重置错误次数
return success(setUserInfo(userInfo));
}
为了便于后续的安全审计和问题排查,我们需要记录用户的登录日志。在上述代码中,我们使用LoginLog
实体类来存储登录日志,并通过loginLogService.save(loginLog, request)
方法将其保存到数据库中。
LoginLog loginLog = new LoginLog();
loginLog.setLoginUser(username);
// ...
loginLogService.save(loginLog, request);
逻辑层实现
@Override
public boolean save(LoginLog loginLog,HttpServletRequest request) {
UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
String operatingSystem = userAgent.getOperatingSystem().getName();
String browserType = userAgent.getBrowser().getName();
String loginIp = "0:0:0:0:0:0:0:1".equals(request.getRemoteAddr()) ? "127.0.0.1" : request.getRemoteAddr();
String location = getLocationByIp(loginIp); // 实现根据 IP 获取地点的方法
loginLog.setOperatingSystem(operatingSystem);
loginLog.setBrowserType(browserType);
loginLog.setLoginIp(loginIp);
loginLog.setLocation(location);
loginLog.setLoginTime(LocalDateTime.now());
return save(loginLog);
}
// 实现根据 IP 获取地点的方法
private String getLocationByIp(String ip) {
// 调用 IP 地址查询服务 API,返回地点信息
String url = "https://www.ip.cn/api/index";
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("ip", ip);
paramMap.put("type", "1");
String result = HttpUtil.get(url, paramMap);
JSONObject tokenInfo = new JSONObject(result);
return tokenInfo.getStr("address").replaceAll("\\s+\\S+$", "");
}
本文通过实际代码示例,详细介绍了Redis在用户登录系统中的应用,包括账号锁定机制和错误次数统计。同时,我们还探讨了如何存储登录日志,以便于后续的安全审计和问题排查。通过合理利用Redis和其他技术手段,我们可以有效提高用户登录系统的安全性和用户体验。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。