refactor: 将请求重复提交和请求限流重构区分为App和Web

This commit is contained in:
valarchie
2023-07-30 11:35:05 +08:00
parent ec8dda127a
commit 3a9fbb563e
5 changed files with 111 additions and 21 deletions

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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
*/