From 44c8a268b3ea22a85655d870f879a93e66bd2ad2 Mon Sep 17 00:00:00 2001 From: Parker Date: Thu, 4 Feb 2021 15:18:23 +0800 Subject: [PATCH] =?UTF-8?q?=E9=AA=8C=E8=AF=81=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- opsli-base-support/opsli-core/pom.xml | 6 +- .../autoconfigure/conf/KaptchaConfig.java | 49 ------- .../core/autoconfigure/conf/ShiroConfig.java | 2 +- .../org/opsli/core/utils/CaptchaUtil.java | 134 ++++++++++++++---- .../system/login/web/LoginRestController.java | 20 +-- pom.xml | 11 +- 6 files changed, 119 insertions(+), 103 deletions(-) delete mode 100644 opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/KaptchaConfig.java diff --git a/opsli-base-support/opsli-core/pom.xml b/opsli-base-support/opsli-core/pom.xml index 2dbaf822..094a8b9e 100644 --- a/opsli-base-support/opsli-core/pom.xml +++ b/opsli-base-support/opsli-core/pom.xml @@ -54,10 +54,10 @@ 3.3.1 - + - com.github.axet - kaptcha + com.github.whvcse + easy-captcha diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/KaptchaConfig.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/KaptchaConfig.java deleted file mode 100644 index e63f2437..00000000 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/KaptchaConfig.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright 2020 OPSLI 快速开发平台 https://www.opsli.com - *

- * 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 org.opsli.core.autoconfigure.conf; - -import com.google.code.kaptcha.impl.DefaultKaptcha; -import com.google.code.kaptcha.util.Config; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.util.Properties; - - -/** - * 生成验证码配置 - * - * @author 孙志强 - - * @date 2017-04-20 19:22 - */ -@Configuration -public class KaptchaConfig { - - @Bean - public DefaultKaptcha producer() { - Properties properties = new Properties(); - properties.put("kaptcha.border", "no"); - properties.put("kaptcha.textproducer.font.color", "black"); - properties.put("kaptcha.textproducer.char.space", "10"); - properties.put("kaptcha.textproducer.char.string", "1234567890"); - properties.put("kaptcha.textproducer.char.length", "4"); - Config config = new Config(properties); - DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); - defaultKaptcha.setConfig(config); - return defaultKaptcha; - } -} diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/ShiroConfig.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/ShiroConfig.java index e545b597..0c6abf7e 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/ShiroConfig.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/ShiroConfig.java @@ -91,7 +91,7 @@ public class ShiroConfig { filterMap.put("/sys/login", "anon"); filterMap.put("/sys/publicKey", "anon"); filterMap.put("/sys/slipCount", "anon"); - filterMap.put("/captcha.jpg", "anon"); + filterMap.put("/captcha*", "anon"); // 导出Excel\模版 不做自动拦截 手动拦截 filterMap.put(apiPathProperties.getGlobalPrefix() + "/**/exportExcel", "anon"); diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/CaptchaUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/CaptchaUtil.java index 8f065ef7..3c8ff26d 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/CaptchaUtil.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/CaptchaUtil.java @@ -15,11 +15,14 @@ */ package org.opsli.core.utils; -import com.google.code.kaptcha.Producer; +import cn.hutool.core.util.RandomUtil; +import com.google.common.collect.Lists; +import com.wf.captcha.ArithmeticCaptcha; +import com.wf.captcha.GifCaptcha; +import com.wf.captcha.SpecCaptcha; +import com.wf.captcha.base.Captcha; import org.apache.commons.lang3.StringUtils; -import org.opsli.common.constants.CacheConstants; import org.opsli.common.exception.TokenException; -import org.opsli.common.utils.Props; import org.opsli.core.cache.local.CacheUtil; import org.opsli.core.msg.TokenMsg; import org.opsli.plugins.redis.RedisPlugin; @@ -28,10 +31,12 @@ import org.springframework.context.annotation.Lazy; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.awt.image.BufferedImage; +import java.io.OutputStream; +import java.util.List; import static org.opsli.common.constants.OrderConstants.UTIL_ORDER; + /** * 验证码 * @@ -41,7 +46,16 @@ import static org.opsli.common.constants.OrderConstants.UTIL_ORDER; @Component @Order(UTIL_ORDER) @Lazy(false) -public class CaptchaUtil{ +public class CaptchaUtil { + + /** 验证码宽度 */ + private static final int CAPTCHA_WIDTH = 180; + /** 验证码高度 */ + private static final int CAPTCHA_HEIGHT = 58; + /** 验证码位数 */ + private static final int CAPTCHA_LEN = 4; + /** 验证码策略 */ + private static final List CAPTCHA_STRATEGY_LIST; /** 缓存前缀 */ private static final String PREFIX = "temp:captcha:"; @@ -49,55 +63,69 @@ public class CaptchaUtil{ private static final int TIME_OUT = 300; /** Redis插件 */ private static RedisPlugin redisPlugin; - /** 谷歌验证码 */ - private static Producer producer; + + static { + CAPTCHA_STRATEGY_LIST = Lists.newArrayListWithCapacity(3); + CAPTCHA_STRATEGY_LIST.add(new CaptchaStrategyBySpec()); + CAPTCHA_STRATEGY_LIST.add(new CaptchaStrategyByGif()); + CAPTCHA_STRATEGY_LIST.add(new CaptchaStrategyByArithmetic()); + } /** * 获得验证码 - * @param uuid UUID - * @return BufferedImage + * + * @param uuid + * @return */ - public static BufferedImage getCaptcha(String uuid) { - if(StringUtils.isBlank(uuid)){ + public static void createCaptcha(String uuid, OutputStream out) { + if (StringUtils.isBlank(uuid)) { throw new RuntimeException("uuid不能为空"); } - //生成文字验证码 - String code = producer.createText(); + // 随机生成验证码 + int randomInt = RandomUtil.randomInt(0, CAPTCHA_STRATEGY_LIST.size()); - boolean ret = redisPlugin.put(CacheUtil.getPrefixName() + PREFIX + uuid, code, TIME_OUT); + // 获得验证码生成策略 + CaptchaStrategy captchaStrategy = CAPTCHA_STRATEGY_LIST.get(randomInt); + // 生成验证码 + Captcha captcha = captchaStrategy.createCaptcha(); + + // 保存至缓存 + boolean ret = redisPlugin.put(CacheUtil.getPrefixName() + PREFIX + uuid, captcha.text(), TIME_OUT); if(ret){ - return producer.createImage(code); + // 输出 + captcha.out(out); } - return null; } /** * 校验验证码 - * @param uuid UUID - * @param code CODE + * + * @param uuid + * @param code + * @return */ public static void validate(String uuid, String code) { // 判断UUID 是否为空 - if(StringUtils.isEmpty(uuid)){ + if (StringUtils.isEmpty(uuid)) { throw new TokenException(TokenMsg.EXCEPTION_CAPTCHA_UUID_NULL); } // 判断 验证码是否为空 - if(StringUtils.isEmpty(code)){ + if (StringUtils.isEmpty(code)) { throw new TokenException(TokenMsg.EXCEPTION_CAPTCHA_CODE_NULL); } // 验证码 String codeTemp = (String) redisPlugin.get(CacheUtil.getPrefixName() + PREFIX + uuid); - if(StringUtils.isEmpty(codeTemp)){ + if (StringUtils.isEmpty(codeTemp)) { throw new TokenException(TokenMsg.EXCEPTION_CAPTCHA_NULL); } // 验证 验证码是否正确 boolean captchaFlag = codeTemp.equalsIgnoreCase(code); - if(!captchaFlag){ + if (!captchaFlag) { throw new TokenException(TokenMsg.EXCEPTION_CAPTCHA_ERROR); } } @@ -105,11 +133,12 @@ public class CaptchaUtil{ /** * 删除验证码 - * @param uuid UUID - * @return boolean + * + * @param uuid + * @return */ public static boolean delCaptcha(String uuid) { - if(StringUtils.isEmpty(uuid)){ + if (StringUtils.isEmpty(uuid)) { return false; } @@ -118,16 +147,61 @@ public class CaptchaUtil{ } - // ========================== @Autowired - public void setRedisPlugin(RedisPlugin redisPlugin) { + public void setRedisPlugin(RedisPlugin redisPlugin) { CaptchaUtil.redisPlugin = redisPlugin; } - @Autowired - public void setProducer(Producer producer) { - CaptchaUtil.producer = producer; + + // ====================== + + public interface CaptchaStrategy{ + + /** + * 生成验证码对象 + * @return Captcha + */ + Captcha createCaptcha(); + } + + /** + * 数字英文混合验证码 静态 + */ + private static class CaptchaStrategyBySpec implements CaptchaStrategy{ + @Override + public Captcha createCaptcha() { + // 生成验证码 + SpecCaptcha captcha = new SpecCaptcha(CAPTCHA_WIDTH, CAPTCHA_HEIGHT, CAPTCHA_LEN); + captcha.setCharType(Captcha.TYPE_DEFAULT); + return captcha; + } + } + + /** + * 数字英文混合验证码 动态 + */ + private static class CaptchaStrategyByGif implements CaptchaStrategy{ + @Override + public Captcha createCaptcha() { + // 生成验证码 + GifCaptcha captcha = new GifCaptcha(CAPTCHA_WIDTH, CAPTCHA_HEIGHT, CAPTCHA_LEN); + captcha.setCharType(Captcha.TYPE_DEFAULT); + return captcha; + } + } + + /** + * 算数验证码 动态 + */ + private static class CaptchaStrategyByArithmetic implements CaptchaStrategy{ + @Override + public Captcha createCaptcha() { + // 生成验证码 + return new ArithmeticCaptcha(CAPTCHA_WIDTH, CAPTCHA_HEIGHT); + } + } + } diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/login/web/LoginRestController.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/login/web/LoginRestController.java index d2809ce7..9e69e1f9 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/login/web/LoginRestController.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/login/web/LoginRestController.java @@ -183,21 +183,13 @@ public class LoginRestController { */ @Limiter(alertType = AlertType.ALERT) @ApiOperation(value = "验证码", notes = "验证码") - @GetMapping("captcha.jpg") + @GetMapping("captcha") public void captcha(String uuid, HttpServletResponse response) throws IOException { - response.setHeader("Cache-Control", "no-store, no-cache"); - response.setContentType("image/jpeg"); - - try { - //获取图片验证码 - BufferedImage image = CaptchaUtil.getCaptcha(uuid); - if(image != null){ - ServletOutputStream out = response.getOutputStream(); - ImageIO.write(image, "jpg", out); - IOUtils.closeQuietly(out); - } - }catch (RuntimeException e){ - OutputStreamUtil.exceptionResponse(e.getMessage(), response); + ServletOutputStream out = response.getOutputStream(); + if(out != null){ + response.setHeader("Cache-Control", "no-store, no-cache"); + //生成图片验证码 + CaptchaUtil.createCaptcha(uuid, out); } } diff --git a/pom.xml b/pom.xml index 60e31b5a..0ad7dcc7 100644 --- a/pom.xml +++ b/pom.xml @@ -71,7 +71,7 @@ 3.9.1 4.5.2 3.9.0 - 0.0.9 + 1.6.2 1.6.0 1.68 @@ -102,14 +102,13 @@ import - + - com.github.axet - kaptcha - ${kaptcha.version} + com.github.whvcse + easy-captcha + ${captcha.version} - com.auth0