refactor: 将请求重复提交和请求限流重构区分为App和Web
This commit is contained in:
@@ -11,6 +11,7 @@ import com.agileboot.domain.system.notice.dto.NoticeDTO;
|
||||
import com.agileboot.domain.system.notice.query.NoticeQuery;
|
||||
import com.agileboot.infrastructure.annotations.AccessLog;
|
||||
import com.agileboot.infrastructure.annotations.Unrepeatable;
|
||||
import com.agileboot.infrastructure.annotations.Unrepeatable.CheckType;
|
||||
import com.agileboot.orm.common.enums.BusinessTypeEnum;
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -85,7 +86,7 @@ public class SysNoticeController extends BaseController {
|
||||
* 新增通知公告
|
||||
*/
|
||||
@Operation(summary = "添加公告")
|
||||
@Unrepeatable(interval = 60)
|
||||
@Unrepeatable(interval = 60, checkType = CheckType.WEB_USER)
|
||||
@PreAuthorize("@permission.has('system:notice:add')")
|
||||
@AccessLog(title = "通知公告", businessType = BusinessTypeEnum.ADD)
|
||||
@PostMapping
|
||||
|
||||
@@ -72,12 +72,26 @@ public @interface RateLimit {
|
||||
},
|
||||
|
||||
/**
|
||||
* 按用户限流
|
||||
* 按Web用户限流
|
||||
*/
|
||||
USER {
|
||||
WEB_USER {
|
||||
@Override
|
||||
public String generateCombinedKey(RateLimit rateLimiter) {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
LoginUser loginUser = AuthenticationUtils.getWebLoginUser();
|
||||
if (loginUser == null) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_NO_AUTHORIZATION);
|
||||
}
|
||||
return rateLimiter.key() + loginUser.getUsername();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 按App用户限流
|
||||
*/
|
||||
APP_USER {
|
||||
@Override
|
||||
public String generateCombinedKey(RateLimit rateLimiter) {
|
||||
LoginUser loginUser = AuthenticationUtils.getAppLoginUser();
|
||||
if (loginUser == null) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_NO_AUTHORIZATION);
|
||||
}
|
||||
@@ -85,6 +99,7 @@ public @interface RateLimit {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public abstract String generateCombinedKey(RateLimit rateLimiter);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
package com.agileboot.infrastructure.annotations;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.infrastructure.security.AuthenticationUtils;
|
||||
import com.agileboot.infrastructure.web.domain.login.LoginUser;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 自定义注解防止表单重复提交
|
||||
@@ -23,4 +28,67 @@ public @interface Unrepeatable {
|
||||
*/
|
||||
int interval() default 5;
|
||||
|
||||
// TODO改成和rate limit一样 可以选择类型
|
||||
|
||||
/**
|
||||
* 检测条件类型
|
||||
*/
|
||||
CheckType checkType() default CheckType.WEB_USER;
|
||||
|
||||
@Slf4j
|
||||
enum CheckType {
|
||||
/**
|
||||
* 按App用户
|
||||
*/
|
||||
APP_USER {
|
||||
@Override
|
||||
public String generateResubmitRedisKey(Method method) {
|
||||
String username;
|
||||
|
||||
try {
|
||||
LoginUser loginUser = AuthenticationUtils.getAppLoginUser();
|
||||
username = loginUser.getUsername();
|
||||
} catch (Exception e) {
|
||||
username = NO_LOGIN;
|
||||
log.error("could not find the related user to check repeatable submit.");
|
||||
}
|
||||
|
||||
return StrUtil.format(RESUBMIT_REDIS_KEY,
|
||||
this.name(),
|
||||
method.getDeclaringClass().getName(),
|
||||
method.getName(),
|
||||
username);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 按Web用户
|
||||
*/
|
||||
WEB_USER {
|
||||
@Override
|
||||
public String generateResubmitRedisKey(Method method) {
|
||||
String username;
|
||||
|
||||
try {
|
||||
LoginUser loginUser = AuthenticationUtils.getWebLoginUser();
|
||||
username = loginUser.getUsername();
|
||||
} catch (Exception e) {
|
||||
username = NO_LOGIN;
|
||||
log.error("could not find the related user to check repeatable submit.");
|
||||
}
|
||||
|
||||
return StrUtil.format(RESUBMIT_REDIS_KEY,
|
||||
this.name(),
|
||||
method.getDeclaringClass().getName(),
|
||||
method.getName(),
|
||||
username);
|
||||
}
|
||||
};
|
||||
|
||||
public static final String NO_LOGIN = "Anonymous";
|
||||
public static final String RESUBMIT_REDIS_KEY = "resubmit:{}:{}:{}:{}";
|
||||
|
||||
public abstract String generateResubmitRedisKey(Method method);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class ResubmitInterceptor extends RequestBodyAdviceAdapter {
|
||||
|
||||
Unrepeatable resubmitAnno = parameter.getMethodAnnotation(Unrepeatable.class);
|
||||
if (resubmitAnno != null) {
|
||||
String redisKey = generateResubmitRedisKey(parameter.getMethod());
|
||||
String redisKey = resubmitAnno.checkType().generateResubmitRedisKey(parameter.getMethod());
|
||||
|
||||
log.info("请求重复提交拦截,当前key:{}, 当前参数:{}", redisKey, currentRequest);
|
||||
|
||||
@@ -74,20 +74,4 @@ public class ResubmitInterceptor extends RequestBodyAdviceAdapter {
|
||||
return body;
|
||||
}
|
||||
|
||||
public String generateResubmitRedisKey(Method method) {
|
||||
String username;
|
||||
|
||||
try {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
username = loginUser.getUsername();
|
||||
} catch (Exception e) {
|
||||
log.warn("未找到对象用户", e);
|
||||
username = NO_LOGIN;
|
||||
}
|
||||
|
||||
return StrUtil.format(RESUBMIT_REDIS_KEY,
|
||||
method.getDeclaringClass().getName(),
|
||||
method.getName(),
|
||||
username);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,28 @@ public class AuthenticationUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取App用户
|
||||
**/
|
||||
public static LoginUser getAppLoginUser() {
|
||||
try {
|
||||
return (LoginUser) getAuthentication().getPrincipal();
|
||||
} catch (Exception e) {
|
||||
throw new ApiException(ErrorCode.Business.USER_FAIL_TO_GET_USER_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取App用户
|
||||
**/
|
||||
public static LoginUser getWebLoginUser() {
|
||||
try {
|
||||
return (LoginUser) getAuthentication().getPrincipal();
|
||||
} catch (Exception e) {
|
||||
throw new ApiException(ErrorCode.Business.USER_FAIL_TO_GET_USER_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Authentication
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user