验证码优化

v1.4.1
Parker 5 years ago
parent 279b1824ed
commit 44c8a268b3

@ -54,10 +54,10 @@
<version>3.3.1</version>
</dependency>
<!-- kaptcha -->
<!-- captcha -->
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>kaptcha</artifactId>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
</dependency>
<!-- JWT -->

@ -1,49 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <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 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;
}
}

@ -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");

@ -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<CaptchaStrategy> 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);
}
}
}

@ -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);
}
}

@ -71,7 +71,7 @@
<oshi.version>3.9.1</oshi.version>
<jna.version>4.5.2</jna.version>
<ehcache.version>3.9.0</ehcache.version>
<kaptcha.version>0.0.9</kaptcha.version>
<captcha.version>1.6.2</captcha.version>
<shiro.version>1.6.0</shiro.version>
<bouncycastle.version>1.68</bouncycastle.version>
@ -102,14 +102,13 @@
<scope>import</scope>
</dependency>
<!-- kaptcha -->
<!-- captcha -->
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>${captcha.version}</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>com.auth0</groupId>

Loading…
Cancel
Save