mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-10-31 10:57:13 +08:00 
			
		
		
		
	refactor: 获取短信、邮箱验证码接口适配 ContiNew Starter 限流器
This commit is contained in:
		| @@ -112,6 +112,12 @@ | |||||||
|             <artifactId>continew-starter-file-excel</artifactId> |             <artifactId>continew-starter-file-excel</artifactId> | ||||||
|         </dependency> |         </dependency> | ||||||
|  |  | ||||||
|  |         <!-- ContiNew Starter 安全模块 - 限流器 --> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>top.continew</groupId> | ||||||
|  |             <artifactId>continew-starter-security-limiter</artifactId> | ||||||
|  |         </dependency> | ||||||
|  |  | ||||||
|         <!-- ContiNew Starter 安全模块 - 加密 --> |         <!-- ContiNew Starter 安全模块 - 加密 --> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>top.continew</groupId> |             <groupId>top.continew</groupId> | ||||||
|   | |||||||
| @@ -63,11 +63,6 @@ public class CaptchaProperties { | |||||||
|          */ |          */ | ||||||
|         private long expirationInMinutes; |         private long expirationInMinutes; | ||||||
|  |  | ||||||
|         /** |  | ||||||
|          * 限制时间 |  | ||||||
|          */ |  | ||||||
|         private long limitInSeconds; |  | ||||||
|  |  | ||||||
|         /** |         /** | ||||||
|          * 模板路径 |          * 模板路径 | ||||||
|          */ |          */ | ||||||
|   | |||||||
| @@ -41,7 +41,7 @@ import org.dromara.sms4j.api.SmsBlend; | |||||||
| import org.dromara.sms4j.api.entity.SmsResponse; | import org.dromara.sms4j.api.entity.SmsResponse; | ||||||
| import org.dromara.sms4j.comm.constant.SupplierConstant; | import org.dromara.sms4j.comm.constant.SupplierConstant; | ||||||
| import org.dromara.sms4j.core.factory.SmsFactory; | import org.dromara.sms4j.core.factory.SmsFactory; | ||||||
| import org.redisson.api.RateType; | import org.redisson.api.RateIntervalUnit; | ||||||
| import org.springframework.http.HttpHeaders; | import org.springframework.http.HttpHeaders; | ||||||
| import org.springframework.validation.annotation.Validated; | import org.springframework.validation.annotation.Validated; | ||||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||||
| @@ -57,6 +57,9 @@ import top.continew.starter.core.util.validate.CheckUtils; | |||||||
| import top.continew.starter.core.util.validate.ValidationUtils; | import top.continew.starter.core.util.validate.ValidationUtils; | ||||||
| import top.continew.starter.log.core.annotation.Log; | import top.continew.starter.log.core.annotation.Log; | ||||||
| import top.continew.starter.messaging.mail.util.MailUtils; | import top.continew.starter.messaging.mail.util.MailUtils; | ||||||
|  | import top.continew.starter.security.limiter.annotation.RateLimiter; | ||||||
|  | import top.continew.starter.security.limiter.annotation.RateLimiters; | ||||||
|  | import top.continew.starter.security.limiter.enums.LimitType; | ||||||
| import top.continew.starter.web.model.R; | import top.continew.starter.web.model.R; | ||||||
|  |  | ||||||
| import java.time.Duration; | import java.time.Duration; | ||||||
| @@ -116,14 +119,28 @@ public class CaptchaController { | |||||||
|         return R.ok(CaptchaResp.builder().uuid(uuid).img(captcha.toBase64()).expireTime(expireTime).build()); |         return R.ok(CaptchaResp.builder().uuid(uuid).img(captcha.toBase64()).expireTime(expireTime).build()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取邮箱验证码 | ||||||
|  |      * | ||||||
|  |      * <p> | ||||||
|  |      * 限流规则:<br> | ||||||
|  |      * 1.同一邮箱同一模板,1分钟2条,1小时8条,24小时20条 <br> | ||||||
|  |      * 2、同一邮箱所有模板 24 小时 100 条 <br> | ||||||
|  |      * 3、同一 IP 每分钟限制发送 30 条 | ||||||
|  |      * </p> | ||||||
|  |      *  | ||||||
|  |      * @param email 邮箱 | ||||||
|  |      * @return / | ||||||
|  |      */ | ||||||
|     @Operation(summary = "获取邮箱验证码", description = "发送验证码到指定邮箱") |     @Operation(summary = "获取邮箱验证码", description = "发送验证码到指定邮箱") | ||||||
|     @GetMapping("/mail") |     @GetMapping("/mail") | ||||||
|  |     @RateLimiters({ | ||||||
|  |         @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX + "MIN", key = "#email + ':' + T(cn.hutool.extra.spring.SpringUtil).getProperty('captcha.mail.templatePath')", rate = 2, interval = 1, unit = RateIntervalUnit.MINUTES, message = "获取验证码操作太频繁,请稍后再试"), | ||||||
|  |         @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX + "HOUR", key = "#email + ':' + T(cn.hutool.extra.spring.SpringUtil).getProperty('captcha.mail.templatePath')", rate = 8, interval = 1, unit = RateIntervalUnit.HOURS, message = "获取验证码操作太频繁,请稍后再试"), | ||||||
|  |         @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX + "DAY'", key = "#email + ':' + T(cn.hutool.extra.spring.SpringUtil).getProperty('captcha.mail.templatePath')", rate = 20, interval = 24, unit = RateIntervalUnit.HOURS, message = "获取验证码操作太频繁,请稍后再试"), | ||||||
|  |         @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX, key = "#email", rate = 100, interval = 24, unit = RateIntervalUnit.HOURS, message = "获取验证码操作太频繁,请稍后再试"), | ||||||
|  |         @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX, key = "#email", rate = 30, interval = 1, unit = RateIntervalUnit.MINUTES, type = LimitType.IP, message = "获取验证码操作太频繁,请稍后再试")}) | ||||||
|     public R<Void> getMailCaptcha(@NotBlank(message = "邮箱不能为空") @Pattern(regexp = RegexPool.EMAIL, message = "邮箱格式错误") String email) throws MessagingException { |     public R<Void> getMailCaptcha(@NotBlank(message = "邮箱不能为空") @Pattern(regexp = RegexPool.EMAIL, message = "邮箱格式错误") String email) throws MessagingException { | ||||||
|         String limitKeyPrefix = CacheConstants.LIMIT_KEY_PREFIX; |  | ||||||
|         String captchaKeyPrefix = CacheConstants.CAPTCHA_KEY_PREFIX; |  | ||||||
|         String limitCaptchaKey = limitKeyPrefix + captchaKeyPrefix + email; |  | ||||||
|         long limitTimeInMillisecond = RedisUtils.getTimeToLive(limitCaptchaKey); |  | ||||||
|         CheckUtils.throwIf(limitTimeInMillisecond > 0, "发送验证码过于频繁,请您 {}s 后再试", limitTimeInMillisecond / 1000); |  | ||||||
|         // 生成验证码 |         // 生成验证码 | ||||||
|         CaptchaProperties.CaptchaMail captchaMail = captchaProperties.getMail(); |         CaptchaProperties.CaptchaMail captchaMail = captchaProperties.getMail(); | ||||||
|         String captcha = RandomUtil.randomNumbers(captchaMail.getLength()); |         String captcha = RandomUtil.randomNumbers(captchaMail.getLength()); | ||||||
| @@ -138,42 +155,40 @@ public class CaptchaController { | |||||||
|             .set("expiration", expirationInMinutes)); |             .set("expiration", expirationInMinutes)); | ||||||
|         MailUtils.sendHtml(email, "【%s】邮箱验证码".formatted(projectProperties.getName()), content); |         MailUtils.sendHtml(email, "【%s】邮箱验证码".formatted(projectProperties.getName()), content); | ||||||
|         // 保存验证码 |         // 保存验证码 | ||||||
|         String captchaKey = captchaKeyPrefix + email; |         String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + email; | ||||||
|         RedisUtils.set(captchaKey, captcha, Duration.ofMinutes(expirationInMinutes)); |         RedisUtils.set(captchaKey, captcha, Duration.ofMinutes(expirationInMinutes)); | ||||||
|         RedisUtils.set(limitCaptchaKey, captcha, Duration.ofSeconds(captchaMail.getLimitInSeconds())); |  | ||||||
|         return R.ok("发送成功,验证码有效期 %s 分钟".formatted(expirationInMinutes)); |         return R.ok("发送成功,验证码有效期 %s 分钟".formatted(expirationInMinutes)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取短信验证码 | ||||||
|  |      * | ||||||
|  |      * <p> | ||||||
|  |      * 限流规则:<br> | ||||||
|  |      * 1.同一号码同一模板,1分钟2条,1小时8条,24小时20条 <br> | ||||||
|  |      * 2、同一号码所有模板 24 小时 100 条 <br> | ||||||
|  |      * 3、同一 IP 每分钟限制发送 30 条 | ||||||
|  |      * </p> | ||||||
|  |      *  | ||||||
|  |      * @param phone      手机号 | ||||||
|  |      * @param captchaReq 行为验证码信息 | ||||||
|  |      * @return / | ||||||
|  |      */ | ||||||
|     @Operation(summary = "获取短信验证码", description = "发送验证码到指定手机号") |     @Operation(summary = "获取短信验证码", description = "发送验证码到指定手机号") | ||||||
|     @GetMapping("/sms") |     @GetMapping("/sms") | ||||||
|  |     @RateLimiters({ | ||||||
|  |         @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX + "MIN", key = "#phone + ':' + T(cn.hutool.extra.spring.SpringUtil).getProperty('captcha.sms.templateId')", rate = 2, interval = 1, unit = RateIntervalUnit.MINUTES, message = "获取验证码操作太频繁,请稍后再试"), | ||||||
|  |         @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX + "HOUR", key = "#phone + ':' + T(cn.hutool.extra.spring.SpringUtil).getProperty('captcha.sms.templateId')", rate = 8, interval = 1, unit = RateIntervalUnit.HOURS, message = "获取验证码操作太频繁,请稍后再试"), | ||||||
|  |         @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX + "DAY'", key = "#phone + ':' + T(cn.hutool.extra.spring.SpringUtil).getProperty('captcha.sms.templateId')", rate = 20, interval = 24, unit = RateIntervalUnit.HOURS, message = "获取验证码操作太频繁,请稍后再试"), | ||||||
|  |         @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX, key = "#phone", rate = 100, interval = 24, unit = RateIntervalUnit.HOURS, message = "获取验证码操作太频繁,请稍后再试"), | ||||||
|  |         @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX, key = "#phone", rate = 30, interval = 1, unit = RateIntervalUnit.MINUTES, type = LimitType.IP, message = "获取验证码操作太频繁,请稍后再试")}) | ||||||
|     public R<Void> getSmsCaptcha(@NotBlank(message = "手机号不能为空") @Pattern(regexp = RegexPool.MOBILE, message = "手机号格式错误") String phone, |     public R<Void> getSmsCaptcha(@NotBlank(message = "手机号不能为空") @Pattern(regexp = RegexPool.MOBILE, message = "手机号格式错误") String phone, | ||||||
|                                  CaptchaVO captchaReq, |                                  CaptchaVO captchaReq) { | ||||||
|                                  HttpServletRequest request) { |  | ||||||
|         // 行为验证码校验 |         // 行为验证码校验 | ||||||
|         ResponseModel verificationRes = behaviorCaptchaService.verification(captchaReq); |         ResponseModel verificationRes = behaviorCaptchaService.verification(captchaReq); | ||||||
|         ValidationUtils.throwIfNotEqual(verificationRes.getRepCode(), RepCodeEnum.SUCCESS.getCode(), verificationRes |         ValidationUtils.throwIfNotEqual(verificationRes.getRepCode(), RepCodeEnum.SUCCESS.getCode(), verificationRes | ||||||
|             .getRepMsg()); |             .getRepMsg()); | ||||||
|         CaptchaProperties.CaptchaSms captchaSms = captchaProperties.getSms(); |         CaptchaProperties.CaptchaSms captchaSms = captchaProperties.getSms(); | ||||||
|         String templateId = captchaSms.getTemplateId(); |  | ||||||
|         String limitKeyPrefix = CacheConstants.LIMIT_KEY_PREFIX; |  | ||||||
|         String captchaKeyPrefix = CacheConstants.CAPTCHA_KEY_PREFIX; |  | ||||||
|         String limitTemplateKeyPrefix = limitKeyPrefix + captchaKeyPrefix; |  | ||||||
|         // 限制短信发送频率 |  | ||||||
|         // 1.同一号码同一短信模板,1分钟2条,1小时8条,24小时20条,e.g. LIMIT:CAPTCHA:XXX:188xxxxx:1 |  | ||||||
|         final String errorMsg = "获取验证码操作太频繁,请稍后再试"; |  | ||||||
|         CheckUtils.throwIf(!RedisUtils.rateLimit(RedisUtils |  | ||||||
|             .formatKey(limitTemplateKeyPrefix + "MIN", phone, templateId), RateType.OVERALL, 2, 60), errorMsg); |  | ||||||
|         CheckUtils.throwIf(!RedisUtils.rateLimit(RedisUtils |  | ||||||
|             .formatKey(limitTemplateKeyPrefix + "HOUR", phone, templateId), RateType.OVERALL, 8, 60 * 60), errorMsg); |  | ||||||
|         CheckUtils.throwIf(!RedisUtils.rateLimit(RedisUtils |  | ||||||
|             .formatKey(limitTemplateKeyPrefix + "DAY", phone, templateId), RateType.OVERALL, 20, 60 * 60 * 24), errorMsg); |  | ||||||
|         // 2.同一号码所有短信模板 24 小时 100 条,e.g. LIMIT:CAPTCHA:188xxxxx |  | ||||||
|         String limitPhoneKey = limitKeyPrefix + captchaKeyPrefix + phone; |  | ||||||
|         CheckUtils.throwIf(!RedisUtils.rateLimit(limitPhoneKey, RateType.OVERALL, 100, 60 * 60 * 24), errorMsg); |  | ||||||
|         // 3.同一 IP 每分钟限制发送 30 条,e.g. LIMIT:CAPTCHA:PHONE:1xx.1xx.1xx.1xx |  | ||||||
|         String limitIpKey = RedisUtils.formatKey(limitKeyPrefix + captchaKeyPrefix + "PHONE", JakartaServletUtil |  | ||||||
|             .getClientIP(request)); |  | ||||||
|         CheckUtils.throwIf(!RedisUtils.rateLimit(limitIpKey, RateType.OVERALL, 30, 60), errorMsg); |  | ||||||
|         // 生成验证码 |         // 生成验证码 | ||||||
|         String captcha = RandomUtil.randomNumbers(captchaSms.getLength()); |         String captcha = RandomUtil.randomNumbers(captchaSms.getLength()); | ||||||
|         // 发送验证码 |         // 发送验证码 | ||||||
| @@ -186,7 +201,7 @@ public class CaptchaController { | |||||||
|             .getTemplateId(), (LinkedHashMap<String, String>)messageMap); |             .getTemplateId(), (LinkedHashMap<String, String>)messageMap); | ||||||
|         CheckUtils.throwIf(!smsResponse.isSuccess(), "验证码发送失败"); |         CheckUtils.throwIf(!smsResponse.isSuccess(), "验证码发送失败"); | ||||||
|         // 保存验证码 |         // 保存验证码 | ||||||
|         String captchaKey = captchaKeyPrefix + phone; |         String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + phone; | ||||||
|         RedisUtils.set(captchaKey, captcha, Duration.ofMinutes(expirationInMinutes)); |         RedisUtils.set(captchaKey, captcha, Duration.ofMinutes(expirationInMinutes)); | ||||||
|         return R.ok("发送成功,验证码有效期 %s 分钟".formatted(expirationInMinutes)); |         return R.ok("发送成功,验证码有效期 %s 分钟".formatted(expirationInMinutes)); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -143,8 +143,6 @@ captcha: | |||||||
|     length: 6 |     length: 6 | ||||||
|     # 过期时间 |     # 过期时间 | ||||||
|     expirationInMinutes: 5 |     expirationInMinutes: 5 | ||||||
|     # 限制时间 |  | ||||||
|     limitInSeconds: 60 |  | ||||||
|     # 模板路径 |     # 模板路径 | ||||||
|     templatePath: mail/captcha.ftl |     templatePath: mail/captcha.ftl | ||||||
|   ## 短信验证码配置 |   ## 短信验证码配置 | ||||||
| @@ -257,8 +255,9 @@ sa-token.extension: | |||||||
|     # 本地存储资源 |     # 本地存储资源 | ||||||
|     - /file/** |     - /file/** | ||||||
|  |  | ||||||
| --- ### 字段加/解密配置 | --- ### 安全配置 | ||||||
| continew-starter.security: | continew-starter.security: | ||||||
|  |   ## 字段加/解密配置 | ||||||
|   crypto: |   crypto: | ||||||
|     enabled: true |     enabled: true | ||||||
|     # 对称加密算法密钥 |     # 对称加密算法密钥 | ||||||
| @@ -266,13 +265,15 @@ continew-starter.security: | |||||||
|     # 非对称加密算法密钥(在线生成 RSA 密钥对:http://web.chacuo.net/netrsakeypair) |     # 非对称加密算法密钥(在线生成 RSA 密钥对:http://web.chacuo.net/netrsakeypair) | ||||||
|     public-key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAM51dgYtMyF+tTQt80sfFOpSV27a7t9uaUVeFrdGiVxscuizE7H8SMntYqfn9lp8a5GH5P1/GGehVjUD2gF/4kcCAwEAAQ== |     public-key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAM51dgYtMyF+tTQt80sfFOpSV27a7t9uaUVeFrdGiVxscuizE7H8SMntYqfn9lp8a5GH5P1/GGehVjUD2gF/4kcCAwEAAQ== | ||||||
|     private-key: MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAznV2Bi0zIX61NC3zSx8U6lJXbtru325pRV4Wt0aJXGxy6LMTsfxIye1ip+f2WnxrkYfk/X8YZ6FWNQPaAX/iRwIDAQABAkEAk/VcAusrpIqA5Ac2P5Tj0VX3cOuXmyouaVcXonr7f+6y2YTjLQuAnkcfKKocQI/juIRQBFQIqqW/m1nmz1wGeQIhAO8XaA/KxzOIgU0l/4lm0A2Wne6RokJ9HLs1YpOzIUmVAiEA3Q9DQrpAlIuiT1yWAGSxA9RxcjUM/1kdVLTkv0avXWsCIE0X8woEjK7lOSwzMG6RpEx9YHdopjViOj1zPVH61KTxAiBmv/dlhqkJ4rV46fIXELZur0pj6WC3N7a4brR8a+CLLQIhAMQyerWl2cPNVtE/8tkziHKbwW3ZUiBXU24wFxedT9iV |     private-key: MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAznV2Bi0zIX61NC3zSx8U6lJXbtru325pRV4Wt0aJXGxy6LMTsfxIye1ip+f2WnxrkYfk/X8YZ6FWNQPaAX/iRwIDAQABAkEAk/VcAusrpIqA5Ac2P5Tj0VX3cOuXmyouaVcXonr7f+6y2YTjLQuAnkcfKKocQI/juIRQBFQIqqW/m1nmz1wGeQIhAO8XaA/KxzOIgU0l/4lm0A2Wne6RokJ9HLs1YpOzIUmVAiEA3Q9DQrpAlIuiT1yWAGSxA9RxcjUM/1kdVLTkv0avXWsCIE0X8woEjK7lOSwzMG6RpEx9YHdopjViOj1zPVH61KTxAiBmv/dlhqkJ4rV46fIXELZur0pj6WC3N7a4brR8a+CLLQIhAMQyerWl2cPNVtE/8tkziHKbwW3ZUiBXU24wFxedT9iV | ||||||
|  |   ## 密码编码器配置 | ||||||
| --- ### 密码编码器配置 |  | ||||||
| continew-starter.security: |  | ||||||
|   password: |   password: | ||||||
|     enabled: true |     enabled: true | ||||||
|     # BCryptPasswordEncoder |     # BCryptPasswordEncoder | ||||||
|     encoding-id: bcrypt |     encoding-id: bcrypt | ||||||
|  |   ## 限流器配置 | ||||||
|  |   limiter: | ||||||
|  |     enabled: true | ||||||
|  |     key-prefix: RateLimiter | ||||||
|  |  | ||||||
| --- ### 文件上传配置 | --- ### 文件上传配置 | ||||||
| spring.servlet: | spring.servlet: | ||||||
|   | |||||||
| @@ -145,8 +145,6 @@ captcha: | |||||||
|     length: 6 |     length: 6 | ||||||
|     # 过期时间 |     # 过期时间 | ||||||
|     expirationInMinutes: 5 |     expirationInMinutes: 5 | ||||||
|     # 限制时间 |  | ||||||
|     limitInSeconds: 60 |  | ||||||
|     # 模板路径 |     # 模板路径 | ||||||
|     templatePath: mail/captcha.ftl |     templatePath: mail/captcha.ftl | ||||||
|   ## 短信验证码配置 |   ## 短信验证码配置 | ||||||
| @@ -254,8 +252,9 @@ sa-token.extension: | |||||||
|     # 本地存储资源 |     # 本地存储资源 | ||||||
|     - /file/** |     - /file/** | ||||||
|  |  | ||||||
| --- ### 字段加/解密配置 | --- ### 安全配置 | ||||||
| continew-starter.security: | continew-starter.security: | ||||||
|  |   ## 字段加/解密配置 | ||||||
|   crypto: |   crypto: | ||||||
|     enabled: true |     enabled: true | ||||||
|     # 对称加密算法密钥 |     # 对称加密算法密钥 | ||||||
| @@ -263,13 +262,15 @@ continew-starter.security: | |||||||
|     # 非对称加密算法密钥(在线生成 RSA 密钥对:http://web.chacuo.net/netrsakeypair) |     # 非对称加密算法密钥(在线生成 RSA 密钥对:http://web.chacuo.net/netrsakeypair) | ||||||
|     public-key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAM51dgYtMyF+tTQt80sfFOpSV27a7t9uaUVeFrdGiVxscuizE7H8SMntYqfn9lp8a5GH5P1/GGehVjUD2gF/4kcCAwEAAQ== |     public-key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAM51dgYtMyF+tTQt80sfFOpSV27a7t9uaUVeFrdGiVxscuizE7H8SMntYqfn9lp8a5GH5P1/GGehVjUD2gF/4kcCAwEAAQ== | ||||||
|     private-key: MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAznV2Bi0zIX61NC3zSx8U6lJXbtru325pRV4Wt0aJXGxy6LMTsfxIye1ip+f2WnxrkYfk/X8YZ6FWNQPaAX/iRwIDAQABAkEAk/VcAusrpIqA5Ac2P5Tj0VX3cOuXmyouaVcXonr7f+6y2YTjLQuAnkcfKKocQI/juIRQBFQIqqW/m1nmz1wGeQIhAO8XaA/KxzOIgU0l/4lm0A2Wne6RokJ9HLs1YpOzIUmVAiEA3Q9DQrpAlIuiT1yWAGSxA9RxcjUM/1kdVLTkv0avXWsCIE0X8woEjK7lOSwzMG6RpEx9YHdopjViOj1zPVH61KTxAiBmv/dlhqkJ4rV46fIXELZur0pj6WC3N7a4brR8a+CLLQIhAMQyerWl2cPNVtE/8tkziHKbwW3ZUiBXU24wFxedT9iV |     private-key: MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAznV2Bi0zIX61NC3zSx8U6lJXbtru325pRV4Wt0aJXGxy6LMTsfxIye1ip+f2WnxrkYfk/X8YZ6FWNQPaAX/iRwIDAQABAkEAk/VcAusrpIqA5Ac2P5Tj0VX3cOuXmyouaVcXonr7f+6y2YTjLQuAnkcfKKocQI/juIRQBFQIqqW/m1nmz1wGeQIhAO8XaA/KxzOIgU0l/4lm0A2Wne6RokJ9HLs1YpOzIUmVAiEA3Q9DQrpAlIuiT1yWAGSxA9RxcjUM/1kdVLTkv0avXWsCIE0X8woEjK7lOSwzMG6RpEx9YHdopjViOj1zPVH61KTxAiBmv/dlhqkJ4rV46fIXELZur0pj6WC3N7a4brR8a+CLLQIhAMQyerWl2cPNVtE/8tkziHKbwW3ZUiBXU24wFxedT9iV | ||||||
|  |   ## 密码编码器配置 | ||||||
| --- ### 密码编码器配置 |  | ||||||
| continew-starter.security: |  | ||||||
|   password: |   password: | ||||||
|     enabled: true |     enabled: true | ||||||
|     # BCryptPasswordEncoder |     # BCryptPasswordEncoder | ||||||
|     encoding-id: bcrypt |     encoding-id: bcrypt | ||||||
|  |   ## 限流器配置 | ||||||
|  |   limiter: | ||||||
|  |     enabled: true | ||||||
|  |     key-prefix: RateLimiter | ||||||
|  |  | ||||||
| --- ### 文件上传配置 | --- ### 文件上传配置 | ||||||
| spring.servlet: | spring.servlet: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user