登录增加限流控制

This commit is contained in:
none 2023-03-10 14:24:36 +08:00
parent f9dec16760
commit 81870bd802
7 changed files with 88 additions and 5 deletions

View File

@ -0,0 +1,32 @@
package xyz.playedu.api.caches;
import org.springframework.stereotype.Component;
import xyz.playedu.api.exception.LimitException;
import xyz.playedu.api.util.RedisUtil;
/**
* @Author 杭州白书科技有限公司
* @create 2023/3/10 14:13
*/
@Component
public class UserLoginCache {
private final static String keyTemplate = "user-login:%s";
private final static int expire = 10;//10s
public void check(String email) throws LimitException {
if (RedisUtil.exists(key(email))) {
throw new LimitException();
}
}
public void put(String email) {
RedisUtil.set(key(email), "1", expire);
}
private String key(String email) {
return String.format(keyTemplate, email);
}
}

View File

@ -9,6 +9,7 @@ import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import xyz.playedu.api.exception.LimitException;
import xyz.playedu.api.exception.NotFoundException;
import xyz.playedu.api.exception.ServiceException;
import xyz.playedu.api.types.JsonResponse;
@ -66,4 +67,9 @@ public class ExceptionController {
return JsonResponse.error(e.getMessage(), 404);
}
@ExceptionHandler(LimitException.class)
public JsonResponse serviceExceptionHandler(LimitException e) {
return JsonResponse.error("请稍后再试", 429);
}
}

View File

@ -7,9 +7,11 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xyz.playedu.api.caches.UserLoginCache;
import xyz.playedu.api.constant.SystemConstant;
import xyz.playedu.api.domain.User;
import xyz.playedu.api.event.UserLoginEvent;
import xyz.playedu.api.exception.LimitException;
import xyz.playedu.api.request.frontend.LoginPasswordRequest;
import xyz.playedu.api.service.JWTService;
import xyz.playedu.api.service.UserService;
@ -39,9 +41,15 @@ public class LoginController {
@Autowired
private ApplicationContext ctx;
@Autowired
private UserLoginCache userLoginCache;
@PostMapping("/password")
public JsonResponse password(@RequestBody @Validated LoginPasswordRequest req) {
User user = userService.find(req.getEmail());
public JsonResponse password(@RequestBody @Validated LoginPasswordRequest req) throws LimitException {
String email = req.getEmail();
userLoginCache.check(email);
User user = userService.find(email);
if (user == null) {
return JsonResponse.error("邮箱未注册");
}
@ -55,7 +63,7 @@ public class LoginController {
data.put("token", token.getToken());
data.put("expired", token.getExpire());
ctx.publishEvent(new UserLoginEvent(this, user.getId(), new Date(), token.getToken(), IpUtil.getIpAddress(), RequestUtil.ua()));
ctx.publishEvent(new UserLoginEvent(this, user.getId(), user.getEmail(), new Date(), token.getToken(), IpUtil.getIpAddress(), RequestUtil.ua()));
return JsonResponse.data(data);
}

View File

@ -17,6 +17,8 @@ public class UserLoginEvent extends ApplicationEvent {
private Integer userId;
private String email;
private Date loginAt;
private String token;
@ -25,9 +27,10 @@ public class UserLoginEvent extends ApplicationEvent {
private UserAgent userAgent;
public UserLoginEvent(Object source, Integer userId, Date loginAt, String token, String ip, UserAgent userAgent) {
public UserLoginEvent(Object source, Integer userId,String email, Date loginAt, String token, String ip, UserAgent userAgent) {
super(source);
this.userId = userId;
this.email = email;
this.loginAt = loginAt;
this.token = token;
this.ip = ip;

View File

@ -0,0 +1,26 @@
package xyz.playedu.api.exception;
/**
* @Author 杭州白书科技有限公司
* @create 2023/3/10 14:13
*/
public class LimitException extends Exception {
public LimitException() {
}
public LimitException(String message) {
super(message);
}
public LimitException(String message, Throwable cause) {
super(message, cause);
}
public LimitException(Throwable cause) {
super(cause);
}
public LimitException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import xyz.playedu.api.caches.UserLoginCache;
import xyz.playedu.api.constant.SystemConstant;
import xyz.playedu.api.event.UserLoginEvent;
import xyz.playedu.api.exception.JwtLogoutException;
@ -27,6 +28,9 @@ public class UserLoginListener {
@Autowired
private JWTService jwtService;
@Autowired
private UserLoginCache userLoginCache;
@EventListener
@Async
public void updateLoginInfo(UserLoginEvent event) throws JwtLogoutException {
@ -44,4 +48,9 @@ public class UserLoginListener {
);
}
@EventListener
public void writeCache(UserLoginEvent event) {
userLoginCache.put(event.getEmail());
}
}

View File

@ -8,7 +8,6 @@ import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import xyz.playedu.api.config.PlayEduConfig;
import xyz.playedu.api.constant.SystemConstant;
import java.util.*;