Remap RequestNotPermittedException with RateLimitExceededException (#4119)

pull/4090/head^2
John Niang 2023-06-26 16:12:54 +08:00 committed by GitHub
parent 8c05a6d30e
commit ecc617c709
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 32 additions and 12 deletions

View File

@ -0,0 +1,15 @@
package run.halo.app.infra.exception;
import java.net.URI;
import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable;
import org.springframework.web.server.ResponseStatusException;
public class RateLimitExceededException extends ResponseStatusException {
public RateLimitExceededException(@Nullable Throwable cause) {
super(HttpStatus.TOO_MANY_REQUESTS, "You have exceeded your quota", cause);
setType(URI.create(Exceptions.REQUEST_NOT_PERMITTED_TYPE));
}
}

View File

@ -1,6 +1,5 @@
package run.halo.app.security.authentication.login;
import static org.springframework.http.HttpStatus.TOO_MANY_REQUESTS;
import static org.springframework.http.HttpStatus.UNAUTHORIZED;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static run.halo.app.infra.exception.Exceptions.createErrorResponse;
@ -39,6 +38,7 @@ import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
import run.halo.app.infra.exception.RateLimitExceededException;
import run.halo.app.infra.utils.IpAddressUtils;
import run.halo.app.security.AdditionalWebFilter;
@ -136,9 +136,9 @@ public class UsernamePasswordAuthenticator implements AdditionalWebFilter {
return RateLimiterOperator.of(rateLimiter);
}
private Mono<Void> handleRequestNotPermitted(RequestNotPermitted e,
private Mono<Void> handleRateLimitExceededException(RateLimitExceededException e,
ServerWebExchange exchange) {
var errorResponse = createErrorResponse(e, TOO_MANY_REQUESTS, exchange, messageSource);
var errorResponse = createErrorResponse(e, null, exchange, messageSource);
return writeErrorResponse(errorResponse, exchange);
}
@ -168,8 +168,9 @@ public class UsernamePasswordAuthenticator implements AdditionalWebFilter {
WebFilterExchange webFilterExchange) {
return super.onAuthenticationSuccess(authentication, webFilterExchange)
.transformDeferred(createIPBasedRateLimiter(webFilterExchange.getExchange()))
.onErrorResume(RequestNotPermitted.class,
e -> handleRequestNotPermitted(e, webFilterExchange.getExchange()));
.onErrorMap(RequestNotPermitted.class, RateLimitExceededException::new)
.onErrorResume(RateLimitExceededException.class,
e -> handleRateLimitExceededException(e, webFilterExchange.getExchange()));
}
}
@ -230,8 +231,9 @@ public class UsernamePasswordAuthenticator implements AdditionalWebFilter {
)
.flatMap(matchResult -> handleAuthenticationException(exception, exchange))
.transformDeferred(createIPBasedRateLimiter(exchange))
.onErrorResume(RequestNotPermitted.class,
e -> handleRequestNotPermitted(e, exchange));
.onErrorMap(RequestNotPermitted.class, RateLimitExceededException::new)
.onErrorResume(RateLimitExceededException.class,
e -> handleRateLimitExceededException(e, exchange));
}
}

View File

@ -11,6 +11,7 @@ import static org.springdoc.core.fn.builders.requestbody.Builder.requestBodyBuil
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
import io.github.resilience4j.reactor.ratelimiter.operator.RateLimiterOperator;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.ArraySchema;
@ -50,6 +51,7 @@ import run.halo.app.extension.router.IListRequest;
import run.halo.app.extension.router.QueryParamBuildUtil;
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
import run.halo.app.infra.exception.AccessDeniedException;
import run.halo.app.infra.exception.RateLimitExceededException;
import run.halo.app.infra.utils.HaloUtils;
import run.halo.app.infra.utils.IpAddressUtils;
import run.halo.app.theme.finders.CommentFinder;
@ -157,8 +159,9 @@ public class CommentFinderEndpoint implements CustomEndpoint {
comment.getSpec().setUserAgent(HaloUtils.userAgentFrom(request));
return commentService.create(comment);
})
.flatMap(comment -> ServerResponse.ok().bodyValue(comment))
.transformDeferred(createIpBasedRateLimiter(request))
.flatMap(comment -> ServerResponse.ok().bodyValue(comment));
.onErrorMap(RequestNotPermitted.class, RateLimitExceededException::new);
}
private <T> RateLimiterOperator<T> createIpBasedRateLimiter(ServerRequest request) {

View File

@ -18,7 +18,7 @@ problemDetail.title.run.halo.app.infra.exception.ThemeUpgradeException=Theme Upg
problemDetail.title.run.halo.app.infra.exception.PluginInstallationException=Plugin Install Error
problemDetail.title.run.halo.app.infra.exception.PluginAlreadyExistsException=Plugin Already Exists Error
problemDetail.title.run.halo.app.infra.exception.DuplicateNameException=Duplicate Name Error
problemDetail.title.io.github.resilience4j.ratelimiter.RequestNotPermitted=Request Not Permitted
problemDetail.title.run.halo.app.infra.exception.RateLimitExceededException=Request Not Permitted
problemDetail.title.internalServerError=Internal Server Error
# Detail definitions
@ -36,7 +36,7 @@ problemDetail.run.halo.app.extension.exception.SchemaViolationException={1} of s
problemDetail.run.halo.app.infra.exception.AttachmentAlreadyExistsException=File {0} already exists, please rename it and try again.
problemDetail.run.halo.app.infra.exception.DuplicateNameException=Duplicate name detected, please rename it and retry.
problemDetail.run.halo.app.infra.exception.PluginAlreadyExistsException=Plugin {0} already exists.
problemDetail.io.github.resilience4j.ratelimiter.RequestNotPermitted=API rate limit exceeded, please try again later.
problemDetail.run.halo.app.infra.exception.RateLimitExceededException=API rate limit exceeded, please try again later.
problemDetail.user.signUpFailed.disallowed=System does not allow new users to register.
problemDetail.user.duplicateName=The username {0} already exists, please rename it and retry.

View File

@ -6,14 +6,14 @@ problemDetail.title.run.halo.app.infra.exception.AttachmentAlreadyExistsExceptio
problemDetail.title.run.halo.app.infra.exception.DuplicateNameException=名称重复
problemDetail.title.run.halo.app.infra.exception.PluginAlreadyExistsException=插件已存在
problemDetail.title.run.halo.app.infra.exception.ThemeInstallationException=主题安装失败
problemDetail.title.io.github.resilience4j.ratelimiter.RequestNotPermitted=请求限制
problemDetail.title.run.halo.app.infra.exception.RateLimitExceededException=请求限制
problemDetail.title.internalServerError=服务器内部错误
problemDetail.org.springframework.security.authentication.BadCredentialsException=用户名或密码错误。
problemDetail.run.halo.app.infra.exception.AttachmentAlreadyExistsException=文件 {0} 已存在,建议更名后重试。
problemDetail.run.halo.app.infra.exception.DuplicateNameException=检测到有重复的名称,请重命名后重试。
problemDetail.run.halo.app.infra.exception.PluginAlreadyExistsException=插件 {0} 已经存。
problemDetail.io.github.resilience4j.ratelimiter.RequestNotPermitted=请求过于频繁,请稍候再试。
problemDetail.run.halo.app.infra.exception.RateLimitExceededException=请求过于频繁,请稍候再试。
problemDetail.user.signUpFailed.disallowed=系统不允许注册新用户。
problemDetail.user.duplicateName=用户名 {0} 已存在,请更换用户名后重试。