diff --git a/playedu-api/src/main/java/xyz/playedu/api/interceptor/AdminInterceptor.java b/playedu-api/src/main/java/xyz/playedu/api/interceptor/AdminInterceptor.java index 03d652c..ebb66c0 100644 --- a/playedu-api/src/main/java/xyz/playedu/api/interceptor/AdminInterceptor.java +++ b/playedu-api/src/main/java/xyz/playedu/api/interceptor/AdminInterceptor.java @@ -21,27 +21,25 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import xyz.playedu.common.bus.BackendBus; -import xyz.playedu.common.config.PlayEduConfig; -import xyz.playedu.common.constant.BackendConstant; import xyz.playedu.common.context.BCtx; import xyz.playedu.common.domain.AdminUser; import xyz.playedu.common.service.AdminUserService; import xyz.playedu.common.service.AppConfigService; import xyz.playedu.common.service.BackendAuthService; -import xyz.playedu.common.service.RateLimiterService; import xyz.playedu.common.types.JsonResponse; import xyz.playedu.common.util.HelperUtil; -import xyz.playedu.common.util.IpUtil; import java.io.IOException; import java.util.Map; @Component @Slf4j +@Order(20) public class AdminInterceptor implements HandlerInterceptor { @Autowired private BackendAuthService authService; @@ -52,28 +50,10 @@ public class AdminInterceptor implements HandlerInterceptor { @Autowired private AppConfigService configService; - @Autowired private RateLimiterService rateLimiterService; - - @Autowired private PlayEduConfig playEduConfig; - @Override public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - // 当前api的请求路径 - String path = request.getRequestURI(); - // 白名单过滤 - if (BackendConstant.API_LIMIT_WHITELIST.contains(path) - || "OPTIONS".equals(request.getMethod())) { - return HandlerInterceptor.super.preHandle(request, response, handler); - } - - String reqCountKey = "api-limiter:" + IpUtil.getIpAddress(); - Long reqCount = rateLimiterService.current(reqCountKey, playEduConfig.getLimiterDuration()); - if (reqCount > playEduConfig.getLimiterLimit()) { - return responseTransform(response, 429, "太多请求"); - } - // 读取全局配置 Map systemConfig = configService.keyValues(); BCtx.setConfig(systemConfig); diff --git a/playedu-api/src/main/java/xyz/playedu/api/interceptor/ApiInterceptor.java b/playedu-api/src/main/java/xyz/playedu/api/interceptor/ApiInterceptor.java new file mode 100644 index 0000000..8c75ab0 --- /dev/null +++ b/playedu-api/src/main/java/xyz/playedu/api/interceptor/ApiInterceptor.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2023 杭州白书科技有限公司 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package xyz.playedu.api.interceptor; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import lombok.extern.slf4j.Slf4j; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +import xyz.playedu.common.config.PlayEduConfig; +import xyz.playedu.common.constant.BackendConstant; +import xyz.playedu.common.service.RateLimiterService; +import xyz.playedu.common.types.JsonResponse; +import xyz.playedu.common.util.HelperUtil; +import xyz.playedu.common.util.IpUtil; + +@Component +@Slf4j +@Order(10) +public class ApiInterceptor implements HandlerInterceptor { + + @Autowired private RateLimiterService rateLimiterService; + + @Autowired private PlayEduConfig playEduConfig; + + @Override + public boolean preHandle( + HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Headers", "*"); + response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); + response.setHeader("Access-Control-Max-Age", "86400"); + + if ("OPTIONS".equals(request.getMethod())) { + response.setStatus(204); + // 返回false意味着整个请求执行到这里结束,不会继续乡下执行了 + return false; + } + + // 当前api的请求路径 + String path = request.getRequestURI(); + // 白名单过滤 || OPTIONS请求 + if (BackendConstant.API_LIMIT_WHITELIST.contains(path)) { + return HandlerInterceptor.super.preHandle(request, response, handler); + } + + // 限流判断 + String reqCountKey = "api-limiter:" + IpUtil.getIpAddress(); + Long reqCount = rateLimiterService.current(reqCountKey, playEduConfig.getLimiterDuration()); + long limitCount = playEduConfig.getLimiterLimit(); + long limitRemaining = limitCount - reqCount; + response.setHeader("X-RateLimit-Limit", String.valueOf(limitCount)); + response.setHeader("X-RateLimit-Remaining", String.valueOf(limitRemaining)); + if (limitRemaining <= 0) { + response.setStatus(429); + response.setContentType("application/json;charset=utf-8"); + response.getWriter().print(HelperUtil.toJsonStr(JsonResponse.error("太多请求"))); + return false; + } + + return HandlerInterceptor.super.preHandle(request, response, handler); + } +} diff --git a/playedu-api/src/main/java/xyz/playedu/api/interceptor/FrontInterceptor.java b/playedu-api/src/main/java/xyz/playedu/api/interceptor/FrontInterceptor.java index a78d5ac..f779b58 100644 --- a/playedu-api/src/main/java/xyz/playedu/api/interceptor/FrontInterceptor.java +++ b/playedu-api/src/main/java/xyz/playedu/api/interceptor/FrontInterceptor.java @@ -21,48 +21,33 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; -import xyz.playedu.common.config.PlayEduConfig; import xyz.playedu.common.constant.FrontendConstant; import xyz.playedu.common.context.FCtx; import xyz.playedu.common.domain.User; import xyz.playedu.common.service.FrontendAuthService; -import xyz.playedu.common.service.RateLimiterService; import xyz.playedu.common.service.UserService; import xyz.playedu.common.types.JsonResponse; import xyz.playedu.common.util.HelperUtil; -import xyz.playedu.common.util.IpUtil; import java.io.IOException; @Component @Slf4j +@Order(20) public class FrontInterceptor implements HandlerInterceptor { @Autowired private FrontendAuthService authService; @Autowired private UserService userService; - @Autowired private RateLimiterService rateLimiterService; - - @Autowired private PlayEduConfig playEduConfig; - @Override public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - if ("OPTIONS".equals(request.getMethod())) { - return HandlerInterceptor.super.preHandle(request, response, handler); - } - - String reqCountKey = "api-limiter:" + IpUtil.getIpAddress(); - Long reqCount = rateLimiterService.current(reqCountKey, playEduConfig.getLimiterDuration()); - if (reqCount > playEduConfig.getLimiterLimit()) { - return responseTransform(response, 429, "太多请求"); - } - if (FrontendConstant.UN_AUTH_URI_WHITELIST.contains(request.getRequestURI())) { return HandlerInterceptor.super.preHandle(request, response, handler); } diff --git a/playedu-api/src/main/java/xyz/playedu/api/interceptor/WebMvcConfig.java b/playedu-api/src/main/java/xyz/playedu/api/interceptor/WebMvcConfig.java index 663bff1..8211a15 100644 --- a/playedu-api/src/main/java/xyz/playedu/api/interceptor/WebMvcConfig.java +++ b/playedu-api/src/main/java/xyz/playedu/api/interceptor/WebMvcConfig.java @@ -15,13 +15,10 @@ */ package xyz.playedu.api.interceptor; -import jakarta.annotation.Resource; - import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -29,23 +26,16 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Slf4j public class WebMvcConfig implements WebMvcConfigurer { - @Resource private AdminInterceptor adminInterceptor; + @Autowired private AdminInterceptor adminInterceptor; @Autowired private FrontInterceptor frontInterceptor; + @Autowired private ApiInterceptor apiInterceptor; + @Override public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(apiInterceptor).addPathPatterns("/**"); registry.addInterceptor(adminInterceptor).addPathPatterns("/backend/**"); registry.addInterceptor(frontInterceptor).addPathPatterns("/api/v1/**"); } - - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**") - .allowCredentials(false) - .allowedOrigins("*") - .allowedHeaders("*") - .allowedMethods("GET", "PUT", "POST", "DELETE") - .exposedHeaders("*"); - } }