效果演示
- 效果
- 等待更新问题
- 点赞存储的
数据键
问题
- 点赞存储的
- 主要实现的功能
- 商品基本的增删改查
- 点赞实现(
Rdis
实现) - 登录禁用使用滑动窗口(
Redis
实现) - 连续错误
3
次后禁用30s
具体实现
- 滑动窗口的实现核心
package com.example.redisapi.service.impl; import com.example.redisapi.domain.LoginAttempt; import com.example.redisapi.domain.User; import com.example.redisapi.domain.vo.ResultVO; import com.example.redisapi.service.LoginService; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.UUID; import java.util.concurrent.TimeUnit; /** * 登录服务实现类 */ @Service public class LoginServiceImpl implements LoginService { /** * 登录尝试键 */ private static final String LOGIN_ATTEMPTS_KEY = "login:attempts:"; /** * 窗口大小,单位毫秒 */ private static final long WINDOW_SIZE = 60 * 1000; /** * 最大登录失败次数 */ private static final int MAX_ATTEMPTS = 3; /** * 冻结账户的前缀 */ private static final String FREEZE_PREFIX = "freeze:"; /** * 冻结时间,单位毫秒 */ private static final long FREEZE_TIME = 30 * 1000; @Resource private RedisTemplate<String, Object> redisTemplate; /** * 登录 * * @param username 用户名 * @param password 密码 * @return 登录结果 */ @Override public ResultVO<String> login(String username, String password) throws JsonProcessingException { String freezeKey = FREEZE_PREFIX + username; // 获取账户冻结状态 Boolean isFrozen = redisTemplate.hasKey(freezeKey); // 账户未冻结 if (!Boolean.TRUE.equals(isFrozen)) { // 登录失败 if (!authenticate(username, password)) { // 记录登录尝试 recordLoginAttempt(username); // 检查并冻结账户 return checkAndFreezeAccount(username); } // 删除之前已经失败的次数 redisTemplate.delete(LOGIN_ATTEMPTS_KEY + username); User user = new User(UUID.randomUUID().toString(), username, password); ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(user); return ResultVO.success("登录成功!", json); } return ResultVO.fail("账户处于冻结中!",isFrozen+""); } /** * 冻结账户 * * @param username 用户名 */ private void freezeAccount(String username) { String freezeKey = FREEZE_PREFIX + username; redisTemplate.opsForValue().set(freezeKey, "", FREEZE_TIME, TimeUnit.MILLISECONDS); } /** * 记录登录尝试 * * @param username 用户名 */ private void recordLoginAttempt(String username) { redisTemplate.opsForZSet().add(LOGIN_ATTEMPTS_KEY + username, new LoginAttempt(username, System.currentTimeMillis()), System.currentTimeMillis()); } /** * 认证 * * @param username 用户名 * @param password 密码 * @return 认证结果 */ private boolean authenticate(String username, String password) { return "admin".equals(username) && "123".equals(password); } /** * 检查并冻结账户 * * @param username 用户名 * @return 检查结果 */ private ResultVO<String> checkAndFreezeAccount(String username) { String loginAttemptsKey = LOGIN_ATTEMPTS_KEY + username; // 统计当前窗口内的登录尝试次数 long count = redisTemplate.opsForZSet().zCard(loginAttemptsKey); // 超过最大登录失败次数,冻结账户 if (count >= MAX_ATTEMPTS) { freezeAccount(username); return ResultVO.fail("账户已冻结!"); } // 删除窗口外的登录尝试记录 redisTemplate.opsForZSet().removeRangeByScore(loginAttemptsKey, 0, System.currentTimeMillis() - WINDOW_SIZE); return ResultVO.fail("失败次数: " + count); } }