mirror of
https://github.com/PlayEdu/PlayEdu
synced 2025-07-25 11:19:40 +08:00
登录增加限流控制
This commit is contained in:
parent
f9dec16760
commit
81870bd802
32
src/main/java/xyz/playedu/api/caches/UserLoginCache.java
Normal file
32
src/main/java/xyz/playedu/api/caches/UserLoginCache.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -9,6 +9,7 @@ import org.springframework.web.bind.MissingServletRequestParameterException;
|
|||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||||
|
import xyz.playedu.api.exception.LimitException;
|
||||||
import xyz.playedu.api.exception.NotFoundException;
|
import xyz.playedu.api.exception.NotFoundException;
|
||||||
import xyz.playedu.api.exception.ServiceException;
|
import xyz.playedu.api.exception.ServiceException;
|
||||||
import xyz.playedu.api.types.JsonResponse;
|
import xyz.playedu.api.types.JsonResponse;
|
||||||
@ -66,4 +67,9 @@ public class ExceptionController {
|
|||||||
return JsonResponse.error(e.getMessage(), 404);
|
return JsonResponse.error(e.getMessage(), 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(LimitException.class)
|
||||||
|
public JsonResponse serviceExceptionHandler(LimitException e) {
|
||||||
|
return JsonResponse.error("请稍后再试", 429);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,11 @@ import org.springframework.web.bind.annotation.PostMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import xyz.playedu.api.caches.UserLoginCache;
|
||||||
import xyz.playedu.api.constant.SystemConstant;
|
import xyz.playedu.api.constant.SystemConstant;
|
||||||
import xyz.playedu.api.domain.User;
|
import xyz.playedu.api.domain.User;
|
||||||
import xyz.playedu.api.event.UserLoginEvent;
|
import xyz.playedu.api.event.UserLoginEvent;
|
||||||
|
import xyz.playedu.api.exception.LimitException;
|
||||||
import xyz.playedu.api.request.frontend.LoginPasswordRequest;
|
import xyz.playedu.api.request.frontend.LoginPasswordRequest;
|
||||||
import xyz.playedu.api.service.JWTService;
|
import xyz.playedu.api.service.JWTService;
|
||||||
import xyz.playedu.api.service.UserService;
|
import xyz.playedu.api.service.UserService;
|
||||||
@ -39,9 +41,15 @@ public class LoginController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ApplicationContext ctx;
|
private ApplicationContext ctx;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserLoginCache userLoginCache;
|
||||||
|
|
||||||
@PostMapping("/password")
|
@PostMapping("/password")
|
||||||
public JsonResponse password(@RequestBody @Validated LoginPasswordRequest req) {
|
public JsonResponse password(@RequestBody @Validated LoginPasswordRequest req) throws LimitException {
|
||||||
User user = userService.find(req.getEmail());
|
String email = req.getEmail();
|
||||||
|
userLoginCache.check(email);
|
||||||
|
|
||||||
|
User user = userService.find(email);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return JsonResponse.error("邮箱未注册");
|
return JsonResponse.error("邮箱未注册");
|
||||||
}
|
}
|
||||||
@ -55,7 +63,7 @@ public class LoginController {
|
|||||||
data.put("token", token.getToken());
|
data.put("token", token.getToken());
|
||||||
data.put("expired", token.getExpire());
|
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);
|
return JsonResponse.data(data);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@ public class UserLoginEvent extends ApplicationEvent {
|
|||||||
|
|
||||||
private Integer userId;
|
private Integer userId;
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
private Date loginAt;
|
private Date loginAt;
|
||||||
|
|
||||||
private String token;
|
private String token;
|
||||||
@ -25,9 +27,10 @@ public class UserLoginEvent extends ApplicationEvent {
|
|||||||
|
|
||||||
private UserAgent userAgent;
|
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);
|
super(source);
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
|
this.email = email;
|
||||||
this.loginAt = loginAt;
|
this.loginAt = loginAt;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.ip = ip;
|
this.ip = ip;
|
||||||
|
26
src/main/java/xyz/playedu/api/exception/LimitException.java
Normal file
26
src/main/java/xyz/playedu/api/exception/LimitException.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import xyz.playedu.api.caches.UserLoginCache;
|
||||||
import xyz.playedu.api.constant.SystemConstant;
|
import xyz.playedu.api.constant.SystemConstant;
|
||||||
import xyz.playedu.api.event.UserLoginEvent;
|
import xyz.playedu.api.event.UserLoginEvent;
|
||||||
import xyz.playedu.api.exception.JwtLogoutException;
|
import xyz.playedu.api.exception.JwtLogoutException;
|
||||||
@ -27,6 +28,9 @@ public class UserLoginListener {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private JWTService jwtService;
|
private JWTService jwtService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserLoginCache userLoginCache;
|
||||||
|
|
||||||
@EventListener
|
@EventListener
|
||||||
@Async
|
@Async
|
||||||
public void updateLoginInfo(UserLoginEvent event) throws JwtLogoutException {
|
public void updateLoginInfo(UserLoginEvent event) throws JwtLogoutException {
|
||||||
@ -44,4 +48,9 @@ public class UserLoginListener {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
public void writeCache(UserLoginEvent event) {
|
||||||
|
userLoginCache.put(event.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import org.springframework.data.redis.core.ScanOptions;
|
|||||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import xyz.playedu.api.config.PlayEduConfig;
|
|
||||||
import xyz.playedu.api.constant.SystemConstant;
|
import xyz.playedu.api.constant.SystemConstant;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user