这篇文章将为大家详细讲解有关SpringBoot整合Redis实现登录失败锁定功能(实例详解),小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
SpringBoot 整合 Redis 实现登录失败锁定功能
简介
在用户登录过程中,防止暴力破解行为是至关重要的。使用 Redis 可以轻松实现登录失败锁定功能,在一定时间内限制用户多次尝试登录失败。
实现步骤
1. 依赖管理
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 配置 Redis 属性
spring.redis.host=localhost
spring.redis.port=6379
3. 创建辅助类
public class LoginAttemptService {
private static final String LOCK_KEY = "login-attempt:";
private RedisTemplate<String, Integer> redisTemplate;
public LoginAttemptService(RedisTemplate<String, Integer> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public void incrementLoginAttempt(String username) {
String key = LOCK_KEY + username;
redisTemplate.opsForValue().increment(key, 1);
redisTemplate.expire(key, 60 * 5, TimeUnit.SECONDS);
}
public int getLoginAttempt(String username) {
String key = LOCK_KEY + username;
Integer attempts = redisTemplate.opsForValue().get(key);
return attempts == null ? 0 : attempts;
}
public void unlock(String username) {
String key = LOCK_KEY + username;
redisTemplate.delete(key);
}
}
4. 集成到 Spring Security
在 AuthenticationFailureHandler
中实现登录失败锁定逻辑:
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
String username = request.getParameter("username");
int attempts = loginAttemptService.getLoginAttempt(username);
if (attempts >= MAX_ATTEMPTS) {
loginAttemptService.unlock(username);
response.setStatus(HttpStatus.FORBIDDEN.value());
return;
}
loginAttemptService.incrementLoginAttempt(username);
}
5. 注入服务
@Configuration
public class RedisConfig {
@Bean
public LoginAttemptService loginAttemptService(RedisTemplate<String, Integer> redisTemplate) {
return new LoginAttemptService(redisTemplate);
}
}
6. 自定义错误消息
在 AuthenticationEntryPoint
中实现自定义错误消息:
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
String username = request.getParameter("username");
int attempts = loginAttemptService.getLoginAttempt(username);
if (attempts >= MAX_ATTEMPTS) {
response.setStatus(HttpStatus.FORBIDDEN.value());
response.getWriter().write("Your account has been locked due to multiple failed login attempts.");
}
}
7. 测试
使用测试用例验证功能:
@ExtendWith(SpringExtension.class)
@WebMvcTest(controllers = LoginController.class, excludeAutoConfiguration = {SecurityAutoConfiguration.class})
class LoginControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private LoginAttemptService loginAttemptService;
@Test
void shouldLockAccountAfterMaxAttempts() throws Exception {
for (int i = 0; i < MAX_ATTEMPTS; i++) {
mockMvc.perform(post("/login")
.param("username", "admin")
.param("password", "wrong-password"))
.andExpect(status().isBadRequest());
}
mockMvc.perform(post("/login")
.param("username", "admin")
.param("password", "wrong-password"))
.andExpect(status().isForbidden());
assertEquals(MAX_ATTEMPTS, loginAttemptService.getLoginAttempt("admin"));
}
@Test
void shouldUnlockAccountAfterTimePeriod() throws Exception {
for (int i = 0; i < MAX_ATTEMPTS; i++) {
mockMvc.perform(post("/login")
.param("username", "admin")
.param("password", "wrong-password"))
.andExpect(status().isBadRequest());
}
Thread.sleep((MAX_ATTEMPTS_TIME + 1) * 1000);
mockMvc.perform(post("/login")
.param("username", "admin")
.param("password", "wrong-password"))
.andExpect(status().isBadRequest());
assertEquals(1, loginAttemptService.getLoginAttempt("admin"));
}
}
以上就是SpringBoot整合Redis实现登录失败锁定功能(实例详解)的详细内容,更多请关注编程学习网其它相关文章!