diff --git a/src/main/java/com/youlai/system/plugin/captcha/CaptchaConfig.java b/src/main/java/com/youlai/system/plugin/captcha/CaptchaConfig.java new file mode 100644 index 00000000..daf6fd35 --- /dev/null +++ b/src/main/java/com/youlai/system/plugin/captcha/CaptchaConfig.java @@ -0,0 +1,55 @@ +package com.youlai.system.plugin.captcha; + +import cn.hutool.captcha.*; +import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.captcha.generator.MathGenerator; +import cn.hutool.captcha.generator.RandomGenerator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.awt.*; + +/** + * 验证码自动装配配置 + * + * @author haoxr + * @since 2023/11/24 + */ +@Configuration +public class CaptchaConfig { + + @Autowired + private CaptchaProperties captchaProperties; + + /** + * 验证码文字生成器 + * + * @return CodeGenerator + */ + @Bean + public CodeGenerator codeGenerator() { + String codeType = captchaProperties.getCode().getType(); + int codeLength = captchaProperties.getCode().getLength(); + if ("math".equalsIgnoreCase(codeType)) { + return new MathGenerator(codeLength); + } else if ("random".equalsIgnoreCase(codeType)) { + return new RandomGenerator(codeLength); + } else { + throw new IllegalArgumentException("Invalid captcha generator type: " + codeType); + } + } + + /** + * 验证码字体 + */ + @Bean + public Font captchaFont() { + String fontName = captchaProperties.getFont().getName(); + int fontSize = captchaProperties.getFont().getSize(); + int fontWight = captchaProperties.getFont().getWeight(); + return new Font(fontName, fontWight, fontSize); + } + + +} diff --git a/src/main/java/com/youlai/system/plugin/captcha/CaptchaGenerator.java b/src/main/java/com/youlai/system/plugin/captcha/CaptchaGenerator.java deleted file mode 100644 index 6ea870df..00000000 --- a/src/main/java/com/youlai/system/plugin/captcha/CaptchaGenerator.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.youlai.system.plugin.captcha; - -import cn.hutool.captcha.AbstractCaptcha; -import cn.hutool.captcha.CircleCaptcha; -import cn.hutool.captcha.generator.CodeGenerator; -import cn.hutool.captcha.generator.MathGenerator; -import cn.hutool.captcha.generator.RandomGenerator; -import com.youlai.system.model.dto.CaptchaResult; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * 验证码自动装配配置 - * - * @author haoxr - * @since 2023/11/24 - */ -@Configuration -public class CaptchaGenerator { - - @Autowired - private CaptchaProperties captchaProperties; - - /** - * 验证码文字生成器 - * - * @return CodeGenerator - */ - @Bean - public CodeGenerator codeGenerator() { - String codeType = captchaProperties.getCode().getType(); - int codeLength = captchaProperties.getCode().getLength(); - if ("math".equalsIgnoreCase(codeType)) { - return new MathGenerator(codeLength); - } else if ("random".equalsIgnoreCase(codeType)) { - return new RandomGenerator(codeLength); - } else { - throw new IllegalArgumentException("Invalid captcha generator type: " + codeType); - } - } - - - /** - * 生成验证码 - * - * @return CaptchaModel 验证码 - */ - public CaptchaModel generate() { - AbstractCaptcha captcha = getCaptcha(); - captcha.createCode(); - return new CaptchaModel(captcha.getCode(), captcha.getImageBase64Data()); - } - - /** - * 验证码类 - * - * @return AbstractCaptcha - */ - public AbstractCaptcha getCaptcha() { - AbstractCaptcha captcha = null; - - String type = captchaProperties.getType(); - int width = captchaProperties.getWidth(); - int height = captchaProperties.getHeight(); - int interfereCount = captchaProperties.getInterfereCount(); - int codeLength = captchaProperties.getCode().getLength(); - - - if ("circle".equalsIgnoreCase(type)) { - captcha = new CircleCaptcha(width, height, codeLength, interfereCount); - } else if ("gif".equalsIgnoreCase(type)) { - return null; - } else if ("line".equalsIgnoreCase(type)) { - return null; - } else if ("shear".equalsIgnoreCase(type)) { - return null; - } else { - throw new IllegalArgumentException("Invalid captcha type: " + type); - } - - captcha.setGenerator(codeGenerator()); - return captcha; - } - - -} diff --git a/src/main/java/com/youlai/system/plugin/captcha/CaptchaModel.java b/src/main/java/com/youlai/system/plugin/captcha/CaptchaModel.java deleted file mode 100644 index cdbc9e44..00000000 --- a/src/main/java/com/youlai/system/plugin/captcha/CaptchaModel.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.youlai.system.plugin.captcha; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * 验证码对象 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -public class CaptchaModel { - /** - * 验证码编码 - */ - private String code; - - /** - * 验证码图片Base64 - */ - private String base64; - -} diff --git a/src/main/java/com/youlai/system/plugin/captcha/CaptchaProperties.java b/src/main/java/com/youlai/system/plugin/captcha/CaptchaProperties.java index 1653a708..9b32f1a5 100644 --- a/src/main/java/com/youlai/system/plugin/captcha/CaptchaProperties.java +++ b/src/main/java/com/youlai/system/plugin/captcha/CaptchaProperties.java @@ -34,6 +34,11 @@ public class CaptchaProperties { */ private int interfereCount; + /** + * 文本透明度 + */ + private Float textAlpha; + /** * 验证码过期时间,单位:秒 */ diff --git a/src/main/java/com/youlai/system/plugin/websocket/WebSocketEventListener.java b/src/main/java/com/youlai/system/plugin/websocket/WebSocketEventListener.java deleted file mode 100644 index e4189d0b..00000000 --- a/src/main/java/com/youlai/system/plugin/websocket/WebSocketEventListener.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.youlai.system.plugin.websocket; - -import cn.hutool.json.JSONUtil; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.event.EventListener; -import org.springframework.stereotype.Component; -import org.springframework.web.socket.messaging.SessionConnectedEvent; -import org.springframework.web.socket.messaging.SessionDisconnectEvent; -import org.springframework.web.socket.messaging.SessionSubscribeEvent; -import org.springframework.web.socket.messaging.SessionUnsubscribeEvent; - -import java.security.Principal; - -/** - * Websocket 客户端事件监听器 - * - * @author haoxr - * @since 2023/10/10 - */ -@Component -@Slf4j -public class WebSocketEventListener { - - /** - * 监听客户端连接事件 - * - * @param event 连接事件对象 - */ - @EventListener - public void handleWebSocketConnectListener(SessionConnectedEvent event) { - Principal user = event.getUser(); - - log.info("客户端连接成功"); - } - - /** - * 监听客户端断开连接事件 - * - * @param event 断开连接事件对象 - */ - @EventListener - public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) { - log.info("客户端断开连接"); - } - - - /** - * 监听客户端订阅事件 - * - * @param event 订阅事件对象 - */ - @EventListener - public void handleSubscription(SessionSubscribeEvent event) { - log.info("客户端订阅:{}", JSONUtil.toJsonStr(event.getMessage())); - } - - /** - * 监听客户端取消订阅事件 - * - * @param event 取消订阅事件对象 - */ - @EventListener - public void handleUnSubscription(SessionUnsubscribeEvent event) { - log.info("客户端取消订阅:{}", JSONUtil.toJsonStr(event.getMessage())); - } - - -} diff --git a/src/main/java/com/youlai/system/service/impl/AuthServiceImpl.java b/src/main/java/com/youlai/system/service/impl/AuthServiceImpl.java index a34e4ed5..ae00fb76 100644 --- a/src/main/java/com/youlai/system/service/impl/AuthServiceImpl.java +++ b/src/main/java/com/youlai/system/service/impl/AuthServiceImpl.java @@ -1,13 +1,14 @@ package com.youlai.system.service.impl; +import cn.hutool.captcha.AbstractCaptcha; +import cn.hutool.captcha.CaptchaUtil; +import cn.hutool.captcha.generator.CodeGenerator; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import com.youlai.system.common.constant.CacheConstants; import com.youlai.system.core.security.jwt.JwtTokenProvider; import com.youlai.system.model.dto.CaptchaResult; import com.youlai.system.model.dto.LoginResult; -import com.youlai.system.plugin.captcha.CaptchaGenerator; -import com.youlai.system.plugin.captcha.CaptchaModel; import com.youlai.system.plugin.captcha.CaptchaProperties; import com.youlai.system.service.AuthService; import io.jsonwebtoken.Claims; @@ -22,6 +23,7 @@ import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; +import java.awt.*; import java.util.Date; import java.util.concurrent.TimeUnit; @@ -38,7 +40,8 @@ public class AuthServiceImpl implements AuthService { private final AuthenticationManager authenticationManager; private final StringRedisTemplate redisTemplate; private final JwtTokenProvider jwtTokenProvider; - private final CaptchaGenerator captchaGenerator; + private final CodeGenerator codeGenerator; + private final Font captchaFont; private final CaptchaProperties captchaProperties; /** @@ -88,16 +91,40 @@ public class AuthServiceImpl implements AuthService { */ @Override public CaptchaResult getCaptcha() { - CaptchaModel captchaModel = captchaGenerator.generate(); + + String type = captchaProperties.getType(); + int width = captchaProperties.getWidth(); + int height = captchaProperties.getHeight(); + int interfereCount = captchaProperties.getInterfereCount(); + int codeLength = captchaProperties.getCode().getLength(); + + AbstractCaptcha captcha; + if ("circle".equalsIgnoreCase(type)) { + captcha = CaptchaUtil.createCircleCaptcha(width, height, codeLength, interfereCount); + } else if ("gif".equalsIgnoreCase(type)) { + captcha = CaptchaUtil.createGifCaptcha(width, height, codeLength); + } else if ("line".equalsIgnoreCase(type)) { + captcha = CaptchaUtil.createLineCaptcha(width, height, codeLength, interfereCount); + } else if ("shear".equalsIgnoreCase(type)) { + captcha = CaptchaUtil.createShearCaptcha(width, height, codeLength, interfereCount); + } else { + throw new IllegalArgumentException("Invalid captcha type: " + type); + } + captcha.setGenerator(codeGenerator); + captcha.setTextAlpha(captchaProperties.getTextAlpha()); + captcha.setFont(captchaFont); + + String captchaCode = captcha.getCode(); + String imageBase64Data = captcha.getImageBase64Data(); // 验证码文本缓存至Redis,用于登录校验 String captchaKey = IdUtil.fastSimpleUUID(); - redisTemplate.opsForValue().set(CacheConstants.CAPTCHA_CODE_PREFIX + captchaKey, captchaModel.getCode(), + redisTemplate.opsForValue().set(CacheConstants.CAPTCHA_CODE_PREFIX + captchaKey,captchaCode, captchaProperties.getExpireSeconds(), TimeUnit.SECONDS); return CaptchaResult.builder() .captchaKey(captchaKey) - .captchaBase64(captchaModel.getBase64()) + .captchaBase64(imageBase64Data) .build(); } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 67c32380..e6dff2eb 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -136,10 +136,12 @@ captcha: # 验证码高度 height: 40 # 验证码干扰元素个数 - interfere-count: 3 + interfere-count: 4 + # 文本透明度(0.0-1.0) + text-alpha: 0.8 # 验证码字符配置 code: - # 验证码字符类型 math-算术 |random-随机字符 + # 验证码字符类型 math-算术|random-随机字符 type: math # 验证码字符长度,type=算术时,表示运算位数(1:个位数运算 2:十位数运算);type=随机字符时,表示字符个数 length: 1 @@ -150,7 +152,7 @@ captcha: # 字体样式 0-普通|1-粗体|2-斜体 weight: 1 # 字体大小 - size: 18 + size: 30 # 验证码有效期(秒) expire-seconds: 120 diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 1869f002..8ce1f49c 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -136,10 +136,12 @@ captcha: # 验证码高度 height: 40 # 验证码干扰元素个数 - interfere-count: 3 + interfere-count: 4 + # 文本透明度(0.0-1.0) + text-alpha: 0.8 # 验证码字符配置 code: - # 验证码字符类型 math-算术 |random-随机字符 + # 验证码字符类型 math-算术|random-随机字符 type: math # 验证码字符长度,type=算术时,表示运算位数(1:个位数运算 2:十位数运算);type=随机字符时,表示字符个数 length: 1 @@ -150,7 +152,7 @@ captcha: # 字体样式 0-普通|1-粗体|2-斜体 weight: 1 # 字体大小 - size: 18 + size: 30 # 验证码有效期(秒) expire-seconds: 120