mirror of
				https://github.com/continew-org/continew-starter.git
				synced 2025-10-31 10:57:15 +08:00 
			
		
		
		
	feat(security/limiter): 新增限流器
This commit is contained in:
		| @@ -0,0 +1,42 @@ | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <parent> | ||||
|         <groupId>top.continew</groupId> | ||||
|         <artifactId>continew-starter-security</artifactId> | ||||
|         <version>${revision}</version> | ||||
|     </parent> | ||||
|  | ||||
|     <artifactId>continew-starter-security-limiter</artifactId> | ||||
|     <description>ContiNew Starter 安全模块 - 限流模块</description> | ||||
|  | ||||
|     <dependencies> | ||||
|         <!-- Redisson(不仅仅是一个 Redis Java 客户端,Redisson 充分的利用了 Redis 键值数据库提供的一系列优势,为使用者提供了一系列具有分布式特性的常用工具:分布式锁、限流器等) --> | ||||
|         <dependency> | ||||
|             <groupId>org.redisson</groupId> | ||||
|             <artifactId>redisson-spring-boot-starter</artifactId> | ||||
|         </dependency> | ||||
|         <!--aop--> | ||||
|         <dependency> | ||||
|             <groupId>org.aspectj</groupId> | ||||
|             <artifactId>aspectjrt</artifactId> | ||||
|             <version>1.9.4</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.aspectj</groupId> | ||||
|             <artifactId>aspectjweaver</artifactId> | ||||
|             <version>1.9.4</version> | ||||
|         </dependency> | ||||
|         <!--hutool--> | ||||
|         <dependency> | ||||
|             <groupId>cn.hutool</groupId> | ||||
|             <artifactId>hutool-all</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!--Redisson缓存 模块--> | ||||
|         <dependency> | ||||
|             <groupId>top.continew</groupId> | ||||
|             <artifactId>continew-starter-cache-redisson</artifactId> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| </project> | ||||
| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * 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 top.continew.starter.security.limiter.annotation; | ||||
|  | ||||
| import org.redisson.api.RateIntervalUnit; | ||||
| import top.continew.starter.security.limiter.enums.LimitType; | ||||
|  | ||||
| import java.lang.annotation.*; | ||||
|  | ||||
| /** | ||||
|  * 限流注解 | ||||
|  * @author KAI | ||||
|  * @since 2.2.0 | ||||
|  */ | ||||
| @Documented | ||||
| @Target(ElementType.METHOD) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| public @interface RateLimiter { | ||||
|  | ||||
|     /** | ||||
|      * LimitType 限流模式 | ||||
|      * DEFAULT 全局限流 | ||||
|      * IP IP限流 | ||||
|      * CLUSTER 实例限流 | ||||
|      */ | ||||
|     LimitType limitType() default LimitType.DEFAULT; | ||||
|  | ||||
|     /** | ||||
|      * 缓存实例名称 | ||||
|      */ | ||||
|     String name() default ""; | ||||
|  | ||||
|     /** | ||||
|      * 限流key 支持 Spring EL 表达式 | ||||
|      */ | ||||
|     String key() default ""; | ||||
|  | ||||
|     /** | ||||
|      * 单位时间产生的令牌数 | ||||
|      */ | ||||
|     int rate() default Integer.MAX_VALUE; | ||||
|  | ||||
|     /** | ||||
|      * 限流时间 | ||||
|      */ | ||||
|     int rateInterval() default 0; | ||||
|  | ||||
|     /** | ||||
|      * 时间单位,默认毫秒 | ||||
|      */ | ||||
|     RateIntervalUnit timeUnit() default RateIntervalUnit.MILLISECONDS; | ||||
|  | ||||
|     /** | ||||
|      * 拒绝请求时的提示信息 | ||||
|      */ | ||||
|     String message() default "您操作过于频繁,请稍后再试!"; | ||||
| } | ||||
| @@ -0,0 +1,33 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * 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 top.continew.starter.security.limiter.annotation; | ||||
|  | ||||
| import java.lang.annotation.*; | ||||
| /** | ||||
|  * 限流组 | ||||
|  * @author KAI | ||||
|  * @since 2.2.0 | ||||
|  */ | ||||
| @Documented | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @Target(ElementType.METHOD) | ||||
| public @interface RateLimiters { | ||||
|     /** | ||||
|      * 用于管理多个 RateLimiter | ||||
|      */ | ||||
|     RateLimiter[] value(); | ||||
| } | ||||
| @@ -0,0 +1,265 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * 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 top.continew.starter.security.limiter.aop; | ||||
|  | ||||
| import cn.hutool.crypto.SecureUtil; | ||||
| import cn.hutool.extra.servlet.JakartaServletUtil; | ||||
| import cn.hutool.extra.spring.SpringUtil; | ||||
| import org.aspectj.lang.JoinPoint; | ||||
| import org.aspectj.lang.ProceedingJoinPoint; | ||||
| import org.aspectj.lang.annotation.Around; | ||||
| import org.aspectj.lang.annotation.Aspect; | ||||
| import org.aspectj.lang.annotation.Pointcut; | ||||
| import org.aspectj.lang.reflect.MethodSignature; | ||||
| import org.redisson.api.*; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.context.expression.BeanFactoryResolver; | ||||
| import org.springframework.context.expression.MethodBasedEvaluationContext; | ||||
| import org.springframework.core.DefaultParameterNameDiscoverer; | ||||
| import org.springframework.core.ParameterNameDiscoverer; | ||||
| import org.springframework.expression.Expression; | ||||
| import org.springframework.expression.ExpressionParser; | ||||
| import org.springframework.expression.ParserContext; | ||||
| import org.springframework.expression.common.TemplateParserContext; | ||||
| import org.springframework.expression.spel.standard.SpelExpressionParser; | ||||
| import org.springframework.stereotype.Component; | ||||
| import org.springframework.util.StringUtils; | ||||
| import top.continew.starter.security.limiter.annotation.RateLimiter; | ||||
| import top.continew.starter.security.limiter.annotation.RateLimiters; | ||||
| import top.continew.starter.security.limiter.autoconfigure.RateLimiterProperties; | ||||
| import top.continew.starter.security.limiter.enums.LimitType; | ||||
| import top.continew.starter.security.limiter.exception.RateLimiterException; | ||||
| import top.continew.starter.web.util.ServletUtils; | ||||
|  | ||||
| import java.util.Objects; | ||||
| import java.util.Optional; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
|  | ||||
| /** | ||||
|  * 限流 AOP 拦截器 | ||||
|  * | ||||
|  * @author KAI | ||||
|  * @since 2.2.0 | ||||
|  */ | ||||
| @Aspect | ||||
| @Component | ||||
| public class RateLimiterAspect { | ||||
|  | ||||
|     private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class); | ||||
|  | ||||
|     private static final ConcurrentHashMap<String, RRateLimiter> rateLimiterCache = new ConcurrentHashMap<>(); | ||||
|  | ||||
|     private static final RedissonClient CLIENT = SpringUtil.getBean(RedissonClient.class); | ||||
|  | ||||
|     private final ParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer(); | ||||
|     private final ExpressionParser parser = new SpelExpressionParser(); | ||||
|     private final ParserContext parserContext = new TemplateParserContext(); | ||||
|  | ||||
|     @Autowired | ||||
|     private RateLimiterProperties rateLimiterProperties; | ||||
|  | ||||
|     /** | ||||
|      * 单个限流注解切点 | ||||
|      */ | ||||
|     @Pointcut("@annotation(top.continew.starter.security.limiter.annotation.RateLimiter)") | ||||
|     public void rateLimiterSinglePointCut() { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 多个限流注解切点 | ||||
|      */ | ||||
|     @Pointcut("@annotation(top.continew.starter.security.limiter.annotation.RateLimiters)") | ||||
|     public void rateLimiterBatchPointCut() { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 环绕通知,处理单个限流注解 | ||||
|      * | ||||
|      * @param joinPoint   切点 | ||||
|      * @param rateLimiter 限流注解 | ||||
|      * @return 返回目标方法的执行结果 | ||||
|      * @throws Throwable 异常 | ||||
|      */ | ||||
|     @Around("@annotation(rateLimiter)") | ||||
|     public Object aroundSingle(ProceedingJoinPoint joinPoint, RateLimiter rateLimiter) throws Throwable { | ||||
|         // 未开启限流功能,直接执行目标方法 | ||||
|         if (!rateLimiterProperties.isEnabled()) { | ||||
|             return joinPoint.proceed(); | ||||
|         } | ||||
|         if (isRateLimited(joinPoint, rateLimiter)) { | ||||
|             throw new RateLimiterException(rateLimiter.message()); | ||||
|         } | ||||
|         return joinPoint.proceed(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 环绕通知,处理多个限流注解 | ||||
|      * | ||||
|      * @param joinPoint    切点 | ||||
|      * @param rateLimiters 多个限流注解 | ||||
|      * @return 返回目标方法的执行结果 | ||||
|      * @throws Throwable 异常 | ||||
|      */ | ||||
|     @Around("@annotation(rateLimiters)") | ||||
|     public Object aroundBatch(ProceedingJoinPoint joinPoint, RateLimiters rateLimiters) throws Throwable { | ||||
|         // 未开启限流功能,直接执行目标方法 | ||||
|         if (!rateLimiterProperties.isEnabled()) { | ||||
|             return joinPoint.proceed(); | ||||
|         } | ||||
|         for (RateLimiter rateLimiter : rateLimiters.value()) { | ||||
|             if (isRateLimited(joinPoint, rateLimiter)) { | ||||
|                 throw new RateLimiterException(rateLimiter.message()); | ||||
|             } | ||||
|         } | ||||
|         return joinPoint.proceed(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 执行限流逻辑 | ||||
|      * | ||||
|      * @param joinPoint   切点 | ||||
|      * @param rateLimiter 限流注解 | ||||
|      * @throws Throwable 异常 | ||||
|      */ | ||||
|     private boolean isRateLimited(ProceedingJoinPoint joinPoint, RateLimiter rateLimiter) throws Throwable { | ||||
|         try { | ||||
|             // 生成限流 Key | ||||
|             String redisKey = generateRedisKey(rateLimiter, joinPoint); | ||||
|             String encipherKey = SecureUtil.md5(redisKey); | ||||
|             // 确定限流类型 | ||||
|             RateType rateType = rateLimiter.limitType() == LimitType.CLUSTER ? RateType.PER_CLIENT : RateType.OVERALL; | ||||
|  | ||||
|             // 获取redisson限流实例 | ||||
|             RRateLimiter rRateLimiter = getRateLimiter(encipherKey); | ||||
|             RateIntervalUnit rateIntervalUnit = rateLimiter.timeUnit(); | ||||
|             int rateInterval = rateLimiter.rateInterval(); | ||||
|             int rate = rateLimiter.rate(); | ||||
|             // 判断是否需要更新限流器 | ||||
|             if (shouldUpdateRateLimiter(rRateLimiter, rateType, rate, rateInterval, rateIntervalUnit)) { | ||||
|                 // 更新限流器 | ||||
|                 rRateLimiter.setRate(rateType, rate, rateInterval, rateIntervalUnit); | ||||
|             } | ||||
|             // 尝试获取令牌 | ||||
|             return !rRateLimiter.tryAcquire(); | ||||
|         } catch (RateLimiterException e) { | ||||
|             throw e; | ||||
|         } catch (Exception e) { | ||||
|             throw new RuntimeException("服务器限流异常,请稍候再试", e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取 Redisson RateLimiter 实例 | ||||
|      * | ||||
|      * @param key 限流器的 Key | ||||
|      * @return RateLimiter 实例 | ||||
|      */ | ||||
|     private RRateLimiter getRateLimiter(String key) { | ||||
|         RRateLimiter rRateLimiter = rateLimiterCache.get(key); | ||||
|         if (rRateLimiter == null) { | ||||
|             // 直接创建 RateLimiter 实例 | ||||
|             rRateLimiter = CLIENT.getRateLimiter(key); | ||||
|             rateLimiterCache.put(key, rRateLimiter); | ||||
|         } | ||||
|         return rRateLimiter; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 判断是否需要更新限流器配置 | ||||
|      * | ||||
|      * @param rRateLimiter     现有的限流器 | ||||
|      * @param rateType         限流类型(OVERALL:全局限流;PER_CLIENT:单机限流) | ||||
|      * @param rate             速率(指定时间间隔产生的令牌数) | ||||
|      * @param rateInterval     速率间隔 | ||||
|      * @param rateIntervalUnit 时间单位 | ||||
|      * @return 是否需要更新配置 | ||||
|      */ | ||||
|     private boolean shouldUpdateRateLimiter(RRateLimiter rRateLimiter, | ||||
|                                             RateType rateType, | ||||
|                                             long rate, | ||||
|                                             long rateInterval, | ||||
|                                             RateIntervalUnit rateIntervalUnit) { | ||||
|  | ||||
|         RateLimiterConfig config = rRateLimiter.getConfig(); | ||||
|         return !Objects.equals(config.getRateType(), rateType) || !Objects.equals(config.getRate(), rate) || !Objects | ||||
|             .equals(config.getRateInterval(), rateIntervalUnit.toMillis(rateInterval)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取限流Key | ||||
|      * | ||||
|      * @param rateLimiter RateLimiter实例 | ||||
|      * @param point       切点 | ||||
|      * @return 限流Key | ||||
|      */ | ||||
|     private String generateRedisKey(RateLimiter rateLimiter, JoinPoint point) { | ||||
|         // 获取限流器配置的 key | ||||
|         String key = rateLimiter.key(); | ||||
|         // 如果 key 不为空,则解析表达式并获取最终的 key | ||||
|         key = Optional.ofNullable(key).map(k -> { | ||||
|             // 获取方法签名 | ||||
|             MethodSignature signature = (MethodSignature)point.getSignature(); | ||||
|             // 获取方法参数 | ||||
|             Object[] args = point.getArgs(); | ||||
|             // 创建表达式上下文 | ||||
|             MethodBasedEvaluationContext context = new MethodBasedEvaluationContext(null, signature | ||||
|                 .getMethod(), args, discoverer); | ||||
|             // 设置 Bean 解析器 | ||||
|             context.setBeanResolver(new BeanFactoryResolver(SpringUtil.getBeanFactory())); | ||||
|             // 解析表达式 | ||||
|             Expression expression; | ||||
|             if (StringUtils.startsWithIgnoreCase(k, parserContext.getExpressionPrefix()) && StringUtils | ||||
|                 .endsWithIgnoreCase(k, parserContext.getExpressionSuffix())) { | ||||
|                 expression = parser.parseExpression(k, parserContext); | ||||
|             } else { | ||||
|                 expression = parser.parseExpression(k); | ||||
|             } | ||||
|             // 获取表达式结果 | ||||
|             return expression.getValue(context, String.class); | ||||
|         }).orElse(key); | ||||
|  | ||||
|         // 拼接最终的 key | ||||
|         StringBuilder redisKey = new StringBuilder(rateLimiterProperties.getLimiterKey()).append(ServletUtils | ||||
|             .getRequest() | ||||
|             .getRequestURI()).append(":"); | ||||
|         //如果缓存name 不为空 则拼接上去 | ||||
|         String name = rateLimiter.name(); | ||||
|         if (StringUtils.hasText(name)) { | ||||
|             redisKey.append(name); | ||||
|             if (!name.endsWith(":")) { | ||||
|                 redisKey.append(":"); | ||||
|             } | ||||
|         } | ||||
|         // 根据限流类型添加不同的信息 | ||||
|         switch (rateLimiter.limitType()) { | ||||
|             case IP: | ||||
|                 // 获取请求 IP | ||||
|                 redisKey.append(JakartaServletUtil.getClientIP(ServletUtils.getRequest())).append(":"); | ||||
|                 break; | ||||
|             case CLUSTER: | ||||
|                 // 获取客户端实例 ID | ||||
|                 redisKey.append(CLIENT.getId()).append(":"); | ||||
|                 break; | ||||
|             default: | ||||
|                 break; | ||||
|         } | ||||
|         // 添加解析后的 key | ||||
|         return redisKey.append(key).toString(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,43 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * 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 top.continew.starter.security.limiter.autoconfigure; | ||||
|  | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| import org.springframework.boot.autoconfigure.AutoConfiguration; | ||||
| import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import top.continew.starter.security.limiter.aop.RateLimiterAspect; | ||||
|  | ||||
| /** | ||||
|  * 限流配置注入器 | ||||
|  * @author KAI | ||||
|  * @since 2.2.0 | ||||
|  */ | ||||
|  | ||||
| @AutoConfiguration | ||||
| @EnableConfigurationProperties(RateLimiterProperties.class) | ||||
| public class RateLimiterAutoConfiguration { | ||||
|  | ||||
|     private static final Logger log = LoggerFactory.getLogger(RateLimiterAutoConfiguration.class); | ||||
|  | ||||
|     @Bean | ||||
|     public RateLimiterAspect rateLimiterAspect() { | ||||
|         log.info("[ContiNew Starter] - Auto Configuration 'RateLimiterAspect' completed initialization."); | ||||
|         return new RateLimiterAspect(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,55 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * 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 top.continew.starter.security.limiter.autoconfigure; | ||||
|  | ||||
| import org.springframework.boot.context.properties.ConfigurationProperties; | ||||
| import org.springframework.util.StringUtils; | ||||
|  | ||||
| /** | ||||
|  * 限流器配置属性 | ||||
|  * @author KAI | ||||
|  * @since 2.2.0 | ||||
|  */ | ||||
| @ConfigurationProperties(prefix = "continew-starter.security.limiter") | ||||
| public class RateLimiterProperties { | ||||
|     private boolean enabled = false; | ||||
|  | ||||
|     private String limiterKey = "RateLimiter:"; | ||||
|  | ||||
|     public boolean isEnabled() { | ||||
|         return enabled; | ||||
|     } | ||||
|  | ||||
|     public void setEnabled(boolean enabled) { | ||||
|         this.enabled = enabled; | ||||
|     } | ||||
|  | ||||
|     public String getLimiterKey() { | ||||
|         return limiterKey; | ||||
|     } | ||||
|  | ||||
|     public void setLimiterKey(String limiterKey) { | ||||
|         //不为空且不以":"结尾,则添加":" | ||||
|         if (StringUtils.hasText(limiterKey)) { | ||||
|             if (!limiterKey.endsWith(":")) { | ||||
|                 limiterKey = limiterKey + ":"; | ||||
|             } | ||||
|         } | ||||
|         this.limiterKey = limiterKey; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,38 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * 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 top.continew.starter.security.limiter.enums; | ||||
|  | ||||
| /** | ||||
|  * 限流类型 | ||||
|  * @author KAI | ||||
|  * @since 2.2.0 | ||||
|  */ | ||||
| public enum LimitType { | ||||
|  | ||||
|     /** | ||||
|      * 全局限流 | ||||
|      */ | ||||
|     DEFAULT, | ||||
|     /** | ||||
|      * 根据IP限流 | ||||
|      */ | ||||
|     IP, | ||||
|     /** | ||||
|      * 根据实例限流(支持集群多实例) | ||||
|      */ | ||||
|     CLUSTER | ||||
| } | ||||
| @@ -0,0 +1,30 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * 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 top.continew.starter.security.limiter.exception; | ||||
|  | ||||
| import top.continew.starter.core.exception.BaseException; | ||||
|  | ||||
| /** | ||||
|  * 限流异常 | ||||
|  * @author KAI | ||||
|  * @since 2.2.0 | ||||
|  */ | ||||
| public class RateLimiterException extends BaseException { | ||||
|     public RateLimiterException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1 @@ | ||||
| top.continew.starter.security.limiter.autoconfigure.RateLimiterAutoConfiguration | ||||
| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|   "top.continew.starter.security.limiter.annotation.RateLimiter@key":{ | ||||
|     "method":{ | ||||
|       "parameters": true | ||||
|     } | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 KAI
					KAI