diff --git a/hyp-admin/src/main/java/com/hyp/web/controller/common/CaptchaController.java b/hyp-admin/src/main/java/com/hyp/web/controller/common/CaptchaController.java deleted file mode 100644 index ecbe715..0000000 --- a/hyp-admin/src/main/java/com/hyp/web/controller/common/CaptchaController.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.hyp.web.controller.common; - -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.util.concurrent.TimeUnit; -import javax.annotation.Resource; -import javax.imageio.ImageIO; -import javax.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.util.FastByteArrayOutputStream; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; -import com.google.code.kaptcha.Producer; -import com.hyp.common.config.HypConfig; -import com.hyp.common.constant.CacheConstants; -import com.hyp.common.constant.Constants; -import com.hyp.common.core.domain.AjaxResult; -import com.hyp.common.core.redis.RedisCache; -import com.hyp.common.utils.sign.Base64; -import com.hyp.common.utils.uuid.IdUtils; -import com.hyp.system.service.ISysConfigService; - -/** - * 验证码操作处理 - * - * @author ruoyi - */ -@RestController -public class CaptchaController -{ - @Resource(name = "captchaProducer") - private Producer captchaProducer; - - @Resource(name = "captchaProducerMath") - private Producer captchaProducerMath; - - @Autowired - private RedisCache redisCache; - - @Autowired - private ISysConfigService configService; - /** - * 生成验证码 - */ - @GetMapping("/captchaImage") - public AjaxResult getCode(HttpServletResponse response) throws IOException - { - AjaxResult ajax = AjaxResult.success(); - boolean captchaEnabled = configService.selectCaptchaEnabled(); - ajax.put("captchaEnabled", captchaEnabled); - if (!captchaEnabled) - { - return ajax; - } - - // 保存验证码信息 - String uuid = IdUtils.simpleUUID(); - String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid; - - String capStr = null, code = null; - BufferedImage image = null; - - // 生成验证码 - String captchaType = HypConfig.getCaptchaType(); - if ("math".equals(captchaType)) - { - String capText = captchaProducerMath.createText(); - capStr = capText.substring(0, capText.lastIndexOf("@")); - code = capText.substring(capText.lastIndexOf("@") + 1); - image = captchaProducerMath.createImage(capStr); - } - else if ("char".equals(captchaType)) - { - capStr = code = captchaProducer.createText(); - image = captchaProducer.createImage(capStr); - } - - redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES); - // 转换流信息写出 - FastByteArrayOutputStream os = new FastByteArrayOutputStream(); - try - { - ImageIO.write(image, "jpg", os); - } - catch (IOException e) - { - return AjaxResult.error(e.getMessage()); - } - - ajax.put("uuid", uuid); - ajax.put("img", Base64.encode(os.toByteArray())); - return ajax; - } -} diff --git a/hyp-admin/src/main/java/com/hyp/web/controller/common/CaptchaEnabledController.java b/hyp-admin/src/main/java/com/hyp/web/controller/common/CaptchaEnabledController.java new file mode 100644 index 0000000..68d9234 --- /dev/null +++ b/hyp-admin/src/main/java/com/hyp/web/controller/common/CaptchaEnabledController.java @@ -0,0 +1,35 @@ +package com.hyp.web.controller.common; + +import com.hyp.common.core.domain.AjaxResult; +import com.hyp.system.service.ISysConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * packageName com.hyp.web.controller.common + * + * @author wangxy + * @version JDK 8 + * @className CaptchaEnabledController + * @date 2024/4/28 + * @description 验证码操作处理 B站、抖音搜索:七维大脑 点个关注呗 + */ + +@RestController +public class CaptchaEnabledController { + + @Autowired + private ISysConfigService configService; + + /** + * 获取验证码开关 + */ + @GetMapping("/captchaEnabled") + public AjaxResult captchaEnabled() { + AjaxResult ajax = AjaxResult.success(); + boolean captchaEnabled = configService.selectCaptchaEnabled(); + ajax.put("captchaEnabled", captchaEnabled); + return ajax; + } +} diff --git a/hyp-admin/src/main/java/com/hyp/web/controller/system/SysLoginController.java b/hyp-admin/src/main/java/com/hyp/web/controller/system/SysLoginController.java index 706f265..00bac51 100644 --- a/hyp-admin/src/main/java/com/hyp/web/controller/system/SysLoginController.java +++ b/hyp-admin/src/main/java/com/hyp/web/controller/system/SysLoginController.java @@ -36,7 +36,7 @@ public class SysLoginController /** * 登录方法 - * + * * @param loginBody 登录信息 * @return 结果 */ @@ -45,12 +45,12 @@ public class SysLoginController { AjaxResult ajax = AjaxResult.success(); // 生成令牌 - String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), - loginBody.getUuid()); + String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode()); ajax.put(Constants.TOKEN, token); return ajax; } + /** * 获取用户信息 * diff --git a/hyp-admin/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService b/hyp-admin/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService new file mode 100644 index 0000000..14a8ed5 --- /dev/null +++ b/hyp-admin/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService @@ -0,0 +1 @@ +com.hyp.framework.web.service.CaptchaRedisService \ No newline at end of file diff --git a/hyp-admin/src/main/resources/application.yml b/hyp-admin/src/main/resources/application.yml index b5f078e..61ac425 100644 --- a/hyp-admin/src/main/resources/application.yml +++ b/hyp-admin/src/main/resources/application.yml @@ -11,7 +11,7 @@ hyp: # 获取ip地址开关 addressEnabled: false # 验证码类型 math 数字计算 char 字符验证 - captchaType: char + # captchaType: char # 开发环境配置 server: @@ -132,3 +132,20 @@ xss: excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/*,/reward/* + +# 滑块验证码 +aj: + captcha: + # 缓存类型 + cache-type: redis + # blockPuzzle 滑块 clickWord 文字点选 default默认两者都实例化 + type: blockPuzzle + # 右下角显示字 + water-mark: + # 校验滑动拼图允许误差偏移量(默认5像素) + slip-offset: 5 + # aes加密坐标开启或者禁用(true|false) + aes-status: true + # 滑动干扰项(0/1/2) + interference-options: 2 + diff --git a/hyp-framework/pom.xml b/hyp-framework/pom.xml index 7e75ceb..d961e1e 100644 --- a/hyp-framework/pom.xml +++ b/hyp-framework/pom.xml @@ -35,16 +35,11 @@ druid-spring-boot-starter - + - pro.fessional - kaptcha - - - servlet-api - javax.servlet - - + com.github.anji-plus + captcha-spring-boot-starter + 1.2.7 diff --git a/hyp-framework/src/main/java/com/hyp/framework/config/CaptchaConfig.java b/hyp-framework/src/main/java/com/hyp/framework/config/CaptchaConfig.java deleted file mode 100644 index 83eb374..0000000 --- a/hyp-framework/src/main/java/com/hyp/framework/config/CaptchaConfig.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.hyp.framework.config; - -import java.util.Properties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import com.google.code.kaptcha.impl.DefaultKaptcha; -import com.google.code.kaptcha.util.Config; -import static com.google.code.kaptcha.Constants.*; - -/** - * 验证码配置 - * - * @author ruoyi - */ -@Configuration -public class CaptchaConfig -{ - @Bean(name = "captchaProducer") - public DefaultKaptcha getKaptchaBean() - { - DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); - Properties properties = new Properties(); - // 是否有边框 默认为true 我们可以自己设置yes,no - properties.setProperty(KAPTCHA_BORDER, "yes"); - // 验证码文本字符颜色 默认为Color.BLACK - properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black"); - // 验证码图片宽度 默认为200 - properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); - // 验证码图片高度 默认为50 - properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); - // 验证码文本字符大小 默认为40 - properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38"); - // KAPTCHA_SESSION_KEY - properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode"); - // 验证码文本字符长度 默认为5 - properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4"); - // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) - properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); - // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy - properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); - Config config = new Config(properties); - defaultKaptcha.setConfig(config); - return defaultKaptcha; - } - - @Bean(name = "captchaProducerMath") - public DefaultKaptcha getKaptchaBeanMath() - { - DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); - Properties properties = new Properties(); - // 是否有边框 默认为true 我们可以自己设置yes,no - properties.setProperty(KAPTCHA_BORDER, "yes"); - // 边框颜色 默认为Color.BLACK - properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90"); - // 验证码文本字符颜色 默认为Color.BLACK - properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue"); - // 验证码图片宽度 默认为200 - properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); - // 验证码图片高度 默认为50 - properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); - // 验证码文本字符大小 默认为40 - properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35"); - // KAPTCHA_SESSION_KEY - properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath"); - // 验证码文本生成器 - properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.hyp.framework.config.KaptchaTextCreator"); - // 验证码文本字符间距 默认为2 - properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3"); - // 验证码文本字符长度 默认为5 - properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6"); - // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) - properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); - // 验证码噪点颜色 默认为Color.BLACK - properties.setProperty(KAPTCHA_NOISE_COLOR, "white"); - // 干扰实现类 - properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise"); - // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy - properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); - Config config = new Config(properties); - defaultKaptcha.setConfig(config); - return defaultKaptcha; - } -} diff --git a/hyp-framework/src/main/java/com/hyp/framework/config/KaptchaTextCreator.java b/hyp-framework/src/main/java/com/hyp/framework/config/KaptchaTextCreator.java deleted file mode 100644 index ca7706f..0000000 --- a/hyp-framework/src/main/java/com/hyp/framework/config/KaptchaTextCreator.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.hyp.framework.config; - -import java.util.Random; -import com.google.code.kaptcha.text.impl.DefaultTextCreator; - -/** - * 验证码文本生成器 - * - * @author ruoyi - */ -public class KaptchaTextCreator extends DefaultTextCreator -{ - private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(","); - - @Override - public String getText() - { - Integer result = 0; - Random random = new Random(); - int x = random.nextInt(10); - int y = random.nextInt(10); - StringBuilder suChinese = new StringBuilder(); - int randomoperands = random.nextInt(3); - if (randomoperands == 0) - { - result = x * y; - suChinese.append(CNUMBERS[x]); - suChinese.append("*"); - suChinese.append(CNUMBERS[y]); - } - else if (randomoperands == 1) - { - if ((x != 0) && y % x == 0) - { - result = y / x; - suChinese.append(CNUMBERS[y]); - suChinese.append("/"); - suChinese.append(CNUMBERS[x]); - } - else - { - result = x + y; - suChinese.append(CNUMBERS[x]); - suChinese.append("+"); - suChinese.append(CNUMBERS[y]); - } - } - else - { - if (x >= y) - { - result = x - y; - suChinese.append(CNUMBERS[x]); - suChinese.append("-"); - suChinese.append(CNUMBERS[y]); - } - else - { - result = y - x; - suChinese.append(CNUMBERS[y]); - suChinese.append("-"); - suChinese.append(CNUMBERS[x]); - } - } - suChinese.append("=?@" + result); - return suChinese.toString(); - } -} \ No newline at end of file diff --git a/hyp-framework/src/main/java/com/hyp/framework/config/SecurityConfig.java b/hyp-framework/src/main/java/com/hyp/framework/config/SecurityConfig.java index 1343ad7..d824481 100644 --- a/hyp-framework/src/main/java/com/hyp/framework/config/SecurityConfig.java +++ b/hyp-framework/src/main/java/com/hyp/framework/config/SecurityConfig.java @@ -110,8 +110,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() // 过滤请求 .authorizeRequests() - // 对于登录login 注册register 验证码captchaImage 允许匿名访问 - .antMatchers("/login", "/register", "/captchaImage","/system/dict/data/type/**").permitAll() + // 对于登录login 注册register 滑块验证码/captcha/get /captcha/check 获取验证码开关 /captchaEnabled 允许匿名访问 + .antMatchers("/login", "/register", "/captcha/get", "/captcha/check", "/captchaEnabled","/system/dict/data/type/**").permitAll() // 静态资源,可匿名访问 .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() diff --git a/hyp-framework/src/main/java/com/hyp/framework/web/service/CaptchaRedisService.java b/hyp-framework/src/main/java/com/hyp/framework/web/service/CaptchaRedisService.java new file mode 100644 index 0000000..07d7f87 --- /dev/null +++ b/hyp-framework/src/main/java/com/hyp/framework/web/service/CaptchaRedisService.java @@ -0,0 +1,58 @@ +package com.hyp.framework.web.service; + +import java.util.concurrent.TimeUnit; +import org.springframework.data.redis.core.StringRedisTemplate; +import com.anji.captcha.service.CaptchaCacheService; + +import javax.annotation.Resource; + +/** + * packageName com.hyp.framework.web.service + * + * @author wangxy + * @version JDK 8 + * @className CaptchaRedisService + * @date 2024/4/28 + * @description + */ +public class CaptchaRedisService implements CaptchaCacheService { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + @Override + public void set(String key, String value, long expiresInSeconds) + { + stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS); + } + + @Override + public boolean exists(String key) + { + return Boolean.TRUE.equals(stringRedisTemplate.hasKey(key)); + } + + @Override + public void delete(String key) + { + stringRedisTemplate.delete(key); + } + + @Override + public String get(String key) + { + return stringRedisTemplate.opsForValue().get(key); + } + + @Override + public Long increment(String key, long val) + { + return stringRedisTemplate.opsForValue().increment(key, val); + } + + @Override + public String type() + { + return "redis"; + } +} diff --git a/hyp-framework/src/main/java/com/hyp/framework/web/service/SysLoginService.java b/hyp-framework/src/main/java/com/hyp/framework/web/service/SysLoginService.java index e74f4f8..4caf93d 100644 --- a/hyp-framework/src/main/java/com/hyp/framework/web/service/SysLoginService.java +++ b/hyp-framework/src/main/java/com/hyp/framework/web/service/SysLoginService.java @@ -1,13 +1,17 @@ package com.hyp.framework.web.service; import javax.annotation.Resource; + +import com.anji.captcha.model.common.ResponseModel; +import com.anji.captcha.model.vo.CaptchaVO; +import com.anji.captcha.service.CaptchaService; +import org.springframework.context.annotation.Lazy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; -import com.hyp.common.constant.CacheConstants; import com.hyp.common.constant.Constants; import com.hyp.common.constant.UserConstants; import com.hyp.common.core.domain.entity.SysUser; @@ -16,7 +20,6 @@ import com.hyp.common.core.redis.RedisCache; import com.hyp.common.exception.ServiceException; import com.hyp.common.exception.user.BlackListException; import com.hyp.common.exception.user.CaptchaException; -import com.hyp.common.exception.user.CaptchaExpireException; import com.hyp.common.exception.user.UserNotExistsException; import com.hyp.common.exception.user.UserPasswordNotMatchException; import com.hyp.common.utils.DateUtils; @@ -52,19 +55,22 @@ public class SysLoginService @Autowired private ISysConfigService configService; + @Autowired + @Lazy + private CaptchaService captchaService; + /** * 登录验证 - * + * * @param username 用户名 * @param password 密码 * @param code 验证码 - * @param uuid 唯一标识 * @return 结果 */ - public String login(String username, String password, String code, String uuid) + public String login(String username, String password, String code) { // 验证码校验 - validateCaptcha(username, code, uuid); + validateCaptcha(username, code); // 登录前置校验 loginPreCheck(username, password); // 用户验证 @@ -102,26 +108,20 @@ public class SysLoginService /** * 校验验证码 - * + * * @param username 用户名 * @param code 验证码 - * @param uuid 唯一标识 * @return 结果 */ - public void validateCaptcha(String username, String code, String uuid) + public void validateCaptcha(String username, String code) { boolean captchaEnabled = configService.selectCaptchaEnabled(); if (captchaEnabled) { - String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, ""); - String captcha = redisCache.getCacheObject(verifyKey); - redisCache.deleteObject(verifyKey); - if (captcha == null) - { - AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"))); - throw new CaptchaExpireException(); - } - if (!code.equalsIgnoreCase(captcha)) + CaptchaVO captchaVO = new CaptchaVO(); + captchaVO.setCaptchaVerification(code); + ResponseModel response = captchaService.verification(captchaVO); + if (!response.isSuccess()) { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))); throw new CaptchaException(); @@ -178,4 +178,5 @@ public class SysLoginService sysUser.setLoginDate(DateUtils.getNowDate()); userService.updateUserProfile(sysUser); } + } diff --git a/hyp-framework/src/main/java/com/hyp/framework/web/service/SysRegisterService.java b/hyp-framework/src/main/java/com/hyp/framework/web/service/SysRegisterService.java index ad84a32..ad67523 100644 --- a/hyp-framework/src/main/java/com/hyp/framework/web/service/SysRegisterService.java +++ b/hyp-framework/src/main/java/com/hyp/framework/web/service/SysRegisterService.java @@ -61,10 +61,10 @@ public class SysRegisterService sysUser.setUserName(username); // 验证码开关 - boolean captchaEnabled = configService.selectCaptchaEnabled(); + /*boolean captchaEnabled = configService.selectCaptchaEnabled(); if (captchaEnabled) { validateCaptcha(username, registerBody.getCode(), registerBody.getUuid()); - } + }*/ if (StringUtils.isEmpty(username)) { msg = "用户名不能为空";