diff --git a/pom.xml b/pom.xml index 04bd089..34df837 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,21 @@ + + + com.baomidou + kisso + 3.8.1 + + + + + com.github.whvcse + easy-captcha + 1.6.2 + + + com.qiniu diff --git a/src/main/java/com/ms/reggie/config/EasyCaptchaConfig.java b/src/main/java/com/ms/reggie/config/EasyCaptchaConfig.java new file mode 100644 index 0000000..ddfa892 --- /dev/null +++ b/src/main/java/com/ms/reggie/config/EasyCaptchaConfig.java @@ -0,0 +1,44 @@ +package com.ms.reggie.config; + +import com.ms.reggie.enums.CodeTypeEnum; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @ClassName EasyCaptchaConfig + * @Author ChangLu + * @Date 4/12/2022 5:28 PM + * @Description 验证码控制器 + */ +@Data +@ConfigurationProperties(prefix = "easycaptcha") +@Configuration +public class EasyCaptchaConfig { + + /** + * 验证码配置 + */ + private CodeTypeEnum codeType; + /** + * 验证码内容长度 + */ + private int length = 4; + /** + * 验证码宽度 + */ + private int width = 111; + /** + * 验证码高度 + */ + private int height = 36; + /** + * 验证码字体 + */ + private String fontName; + /** + * 字体大小 + */ + private int fontSize = 25; + +} diff --git a/src/main/java/com/ms/reggie/config/SpringConfiguration.java b/src/main/java/com/ms/reggie/config/SpringConfiguration.java new file mode 100644 index 0000000..18ad572 --- /dev/null +++ b/src/main/java/com/ms/reggie/config/SpringConfiguration.java @@ -0,0 +1,31 @@ +package com.ms.reggie.config; + +import com.baomidou.kisso.captcha.ImageCaptcha; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + *

+ *

+ * + * @author SerMs + * @date 2022/6/21 23:38 + */ +@Configuration +public class SpringConfiguration { + @Bean + public ImageCaptcha imageCaptcha() { + ImageCaptcha imageCaptcha = ImageCaptcha.getInstance(); + // 干扰量 1 + imageCaptcha.setInterfere(1); + // 验证码内容长度 4 位 + imageCaptcha.setLength(4); + // Gif 验证码 + // imageCaptcha.setGif(true); + // 验证码存储处理类,默认存在在 session 实现类 CaptchaStoreSession 仅适用单机 + // 分布式可以采用 Redis 处理,例如 RedisCaptchaStore 实现 ICaptchaStore 接口 + // imageCaptcha.setCaptchaStore(new CaptchaStoreRedis()); + return imageCaptcha; + } + +} diff --git a/src/main/java/com/ms/reggie/controller/CaptchaController.java b/src/main/java/com/ms/reggie/controller/CaptchaController.java new file mode 100644 index 0000000..5b952d5 --- /dev/null +++ b/src/main/java/com/ms/reggie/controller/CaptchaController.java @@ -0,0 +1,64 @@ +package com.ms.reggie.controller; + +import com.baomidou.kisso.captcha.ICaptcha; +import com.wf.captcha.SpecCaptcha; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + *

+ *

+ * + * @author SerMs + * @date 2022/6/21 23:29 + */ +@RestController +@RequestMapping("/captcha") +public class CaptchaController { + @Resource + protected HttpServletRequest request; + @Resource + protected HttpServletResponse response; + @Resource + private ICaptcha captcha; + + @RequestMapping("/hello") + public void hello(HttpServletResponse response) throws IOException { + // png类型 + SpecCaptcha captcha = new SpecCaptcha(130, 48); + String text = captcha.text();// 获取验证码的字符 + char[] chars = captcha.textChar();// 获取验证码的字符数组 + + System.out.println("验证码:" + text); + System.out.println(chars); + // 输出验证码 + captcha.out(response.getOutputStream()); + } + + + // 生成验证,例如:http://localhost:8088/v1/captcha/image?ticket=123456 + @GetMapping("image") + public void image(String ticket) { + try { + // 验证码信息存放在缓存中,key = ticket 、 value = 验证码文本内容 + captcha.generate(request, response.getOutputStream(), ticket); + } catch (IOException e) { + e.printStackTrace(); + } + } + + // 校验图片验证码 123321 + @PostMapping("verification") + public boolean verification(String ticket, String code) { + // ticket 为生成验证码的票据, code 为图片验证码文本内容 + return captcha.verification(request, ticket, code); + } +} + diff --git a/src/main/java/com/ms/reggie/controller/EasyCaptchaController.java b/src/main/java/com/ms/reggie/controller/EasyCaptchaController.java new file mode 100644 index 0000000..cced9fd --- /dev/null +++ b/src/main/java/com/ms/reggie/controller/EasyCaptchaController.java @@ -0,0 +1,54 @@ +package com.ms.reggie.controller; + +import com.ms.reggie.enums.CodeTypeEnum; +import com.ms.reggie.service.EasyCaptchaService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +/** + * @ClassName CaptchaController + * @Author ChangLu + * @Date 4/12/2022 5:44 PM + * @Description Easy-captcha控制器 + */ +@Controller +@RestController +public class EasyCaptchaController { + + @Autowired + private EasyCaptchaService easyCaptchaService; + + //1、算术类型 + @GetMapping("/captcha1") + public Map getGifcCaptcha1() { + return easyCaptchaService.getCaptchaValueAndBase64(null); + } + + //2、Gif + @GetMapping("/captcha2") + public Map getGifcCaptcha2() { + return easyCaptchaService.getCaptchaValueAndBase64(CodeTypeEnum.GIF); + } + + //3、png类型 + @GetMapping("/captcha3") + public Map getGifcCaptcha3() { + return easyCaptchaService.getCaptchaValueAndBase64(CodeTypeEnum.SPEC); + } + + //4、chinese文字类型 + @GetMapping("/captcha4") + public Map getGifcCaptcha4() { + return easyCaptchaService.getCaptchaValueAndBase64(CodeTypeEnum.CHINESE); + } + + //4、chinese Gif类型 + @GetMapping("/captcha5") + public Map getGifcCaptcha5() { + return easyCaptchaService.getCaptchaValueAndBase64(CodeTypeEnum.CHINESE_GIF); + } +} diff --git a/src/main/java/com/ms/reggie/controller/UserController.java b/src/main/java/com/ms/reggie/controller/UserController.java index eca192a..1fd372c 100644 --- a/src/main/java/com/ms/reggie/controller/UserController.java +++ b/src/main/java/com/ms/reggie/controller/UserController.java @@ -4,14 +4,11 @@ import com.ms.reggie.pojo.User; import com.ms.reggie.service.UserService; import com.ms.reggie.util.R; +import com.ms.reggie.util.SendMessageUtil; import com.ms.reggie.util.ValidateCodeUtils; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.StringUtils; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpSession; @@ -39,15 +36,26 @@ public class UserController { private RedisTemplate redisTemplate; @PostMapping("/sendMsg") - public R sendMsg(@RequestBody User user, HttpSession session) { - //获取手机号 - String phone = user.getPhone(); - if (StringUtils.isNotEmpty(phone)) { + public R sendMsg(@RequestParam String key, + @RequestParam String phone, + @RequestParam String captcha, HttpSession session) { + log.info("=====验证码获取==={}===={}===={}", key, captcha, phone); + //从Redis获取缓存的图形验证码 + boolean msg = false; + Object codeInSession = redisTemplate.opsForValue().get(key); + if (codeInSession != null && codeInSession.equals(captcha)) { + //删除redis + //如果登录成功,就删除缓存的验证码 + redisTemplate.delete(key); + log.info("删除验证码"); + msg = true; + } + if (msg) { //生成随机的四位随机数 String code = ValidateCodeUtils.generateValidateCode(6).toString(); //调用短信服务 -// Integer resultCode = SendMessageUtil.send(phone, "您正在登录湘约楼平台,请妥善保管您得验证码" + code); -// log.info("生成的验证码为:{},{}", code, SendMessageUtil.getMessage(resultCode)); + Integer resultCode = SendMessageUtil.send(phone, "您正在登录湘约楼平台,请妥善保管您得验证码" + code); + log.info("生成的验证码为:{},{}", code, SendMessageUtil.getMessage(resultCode)); //需要将生成的验证码保存到Session log.info("验证码为:{}", code); @@ -69,7 +77,6 @@ public R login(@RequestBody Map map, HttpSession session) { log.info("map:{}", map.toString()); //获取手机号 String phone = map.get("phone").toString(); - //获取验证码 String code = map.get("code").toString(); diff --git a/src/main/java/com/ms/reggie/enums/CodeTypeEnum.java b/src/main/java/com/ms/reggie/enums/CodeTypeEnum.java new file mode 100644 index 0000000..1a94594 --- /dev/null +++ b/src/main/java/com/ms/reggie/enums/CodeTypeEnum.java @@ -0,0 +1,29 @@ +package com.ms.reggie.enums; + +/** + * @ClassName CodeTypeEnum + * @Author ChangLu + * @Date 4/12/2022 5:29 PM + * @Description 验证码类型枚举类 + */ +public enum CodeTypeEnum { + + /** + * 算数 + */ + ARITHMETIC, + /** + * 中文 + */ + CHINESE, + /** + * 中文闪图 + */ + CHINESE_GIF, + /** + * 闪图 + */ + GIF, + SPEC + +} diff --git a/src/main/java/com/ms/reggie/filter/LoginCheckFilter.java b/src/main/java/com/ms/reggie/filter/LoginCheckFilter.java index 65b8916..84418af 100644 --- a/src/main/java/com/ms/reggie/filter/LoginCheckFilter.java +++ b/src/main/java/com/ms/reggie/filter/LoginCheckFilter.java @@ -51,8 +51,10 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo "/webjars/**", "/swagger-resources", "/v2/api-docs", - "/qiniukodo/**", - "/dish/categoiryList" + "/captcha/**", + "/captcha1/**", +// "/qiniukodo/**", +// "/dish/categoiryList" }; //判断本次请求是否需要处理 diff --git a/src/main/java/com/ms/reggie/service/EasyCaptchaService.java b/src/main/java/com/ms/reggie/service/EasyCaptchaService.java new file mode 100644 index 0000000..29a20d5 --- /dev/null +++ b/src/main/java/com/ms/reggie/service/EasyCaptchaService.java @@ -0,0 +1,77 @@ +package com.ms.reggie.service; + +import com.ms.reggie.enums.CodeTypeEnum; +import com.ms.reggie.util.EasyCaptchaProducer; +import com.wf.captcha.base.Captcha; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * @ClassName EasyCaptchaService + * @Author ChangLu + * @Date 4/12/2022 6:20 PM + * @Description easy-captcha业务工具类 + */ +@Service +@Slf4j +public class EasyCaptchaService { + + @Resource + private EasyCaptchaProducer easyCaptchaProducer; + + @Resource + private RedisTemplate redisTemplate; + + /** + * 获取指定类型的验证码结果以及Base64编码值 + * + * @param codeType 验证码类型 + * @return + */ + public Map getCaptchaValueAndBase64(CodeTypeEnum codeType) { + Captcha captcha = null; + if (codeType == null) { + captcha = easyCaptchaProducer.getCaptcha(); + } else { + captcha = easyCaptchaProducer.getCaptcha(codeType); + } + //1、获取到结果值 + String captchaValue = captcha.text().toLowerCase(); + log.info("===结果值:{}", captchaValue); + //获取key + String key = UUID.randomUUID().toString(); + //存入Redis + String verifyKey = "captcha_codes" + key; + log.info("====={}===={}", verifyKey, captchaValue); + redisTemplate.opsForValue().set(verifyKey, captchaValue, 4, TimeUnit.MINUTES); + //对于数学类型的需要进行处理 + if (codeType == null || codeType == CodeTypeEnum.ARITHMETIC) { + if (captcha.getCharType() - 1 == CodeTypeEnum.ARITHMETIC.ordinal() && captchaValue.contains(".")) { + captchaValue = captchaValue.split("\\.")[0]; + } + } + //2、获取到Base64编码 + String captchaBase64 = captcha.toBase64(); + Map result = new HashMap<>(2); + result.put("key", verifyKey); //生成的uuid + result.put("base64", captchaBase64); //生成的64格式验证码 + return result; + + /* + * + * //从Redis获取缓存的验证码 + Object codeInSession = redisTemplate.opsForValue().get(phone); + //如果登录成功,就删除缓存的验证码 + redisTemplate.delete(phone); + + * */ + } + +} diff --git a/src/main/java/com/ms/reggie/util/EasyCaptchaProducer.java b/src/main/java/com/ms/reggie/util/EasyCaptchaProducer.java new file mode 100644 index 0000000..2d45597 --- /dev/null +++ b/src/main/java/com/ms/reggie/util/EasyCaptchaProducer.java @@ -0,0 +1,92 @@ +package com.ms.reggie.util; + +import com.ms.reggie.config.EasyCaptchaConfig; +import com.ms.reggie.enums.CodeTypeEnum; +import com.wf.captcha.*; +import com.wf.captcha.base.Captcha; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @ClassName EasyCaptchaProducer + * @Author ChangLu + * @Date 4/12/2022 5:35 PM + * @Description 验证码生成器 + */ +@Component +public class EasyCaptchaProducer { + + @Autowired + private EasyCaptchaConfig easyCaptchaConfig; + + /** + * 自定义选择类型 + */ + public Captcha getCaptcha(CodeTypeEnum codeType) { + easyCaptchaConfig.setCodeType(codeType); + return switchCaptcha(easyCaptchaConfig); + } + + /** + * 获取默认配置captcha + */ + public Captcha getCaptcha() { + return switchCaptcha(easyCaptchaConfig); + } + + + private Captcha switchCaptcha(EasyCaptchaConfig config) { + Captcha captcha; + switch (config.getCodeType()) { + case ARITHMETIC: + // 算术类型 https://gitee.com/whvse/EasyCaptcha + captcha = new FixedArithmeticCaptcha(config.getWidth(), config.getHeight()); + //固定设置为两位,图片为算数运算表达式 + captcha.setLen(2); + break; + case CHINESE: + captcha = new ChineseCaptcha(config.getWidth(), config.getHeight()); + captcha.setLen(config.getLength()); + break; + case CHINESE_GIF: + captcha = new ChineseGifCaptcha(config.getWidth(), config.getHeight()); + captcha.setLen(config.getLength()); + break; + case GIF: + captcha = new GifCaptcha(config.getWidth(), config.getHeight());//最后一位是位数 + captcha.setLen(config.getLength()); + break; + case SPEC: + captcha = new SpecCaptcha(config.getWidth(), config.getHeight()); + captcha.setLen(config.getLength()); + break; + default: + throw new RuntimeException("验证码配置信息错误!正确配置查看 LoginCodeEnum "); + } + return captcha; + } + + static class FixedArithmeticCaptcha extends ArithmeticCaptcha { + public FixedArithmeticCaptcha(int width, int height) { + super(width, height); + } + + @Override + protected char[] alphas() { + // 生成随机数字和运算符 + int n1 = num(1, 10), n2 = num(1, 10); + int opt = num(3); + + // 计算结果 + int res = new int[]{n1 + n2, n1 - n2, n1 * n2}[opt]; + // 转换为字符运算符 + char optChar = "+-x".charAt(opt); + + this.setArithmeticString(String.format("%s%c%s=?", n1, optChar, n2)); + this.chars = String.valueOf(res); + + return chars.toCharArray(); + } + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 90dd3da..917f58c 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -83,4 +83,9 @@ qiniu: accessKey: ID_Vi-bQ_x43W3KSxy8y9WuaAp2H38tYEM3tslEF secretKey: 6qU71m1te4NKQI1ue5bmCL97x9eeaX5Zrih9AtCl bucket: serms - domain: https://serms.xyz/ \ No newline at end of file + domain: https://serms.xyz/ + +# easy-captcha配置 +easycaptcha: + # 验证码类型配置 查看 LoginProperties 类 + code-type: arithmetic \ No newline at end of file diff --git a/target/classes/application.yml b/target/classes/application.yml index 90dd3da..29cd93a 100644 --- a/target/classes/application.yml +++ b/target/classes/application.yml @@ -83,4 +83,9 @@ qiniu: accessKey: ID_Vi-bQ_x43W3KSxy8y9WuaAp2H38tYEM3tslEF secretKey: 6qU71m1te4NKQI1ue5bmCL97x9eeaX5Zrih9AtCl bucket: serms - domain: https://serms.xyz/ \ No newline at end of file + domain: https://serms.xyz/ + +# easy-captcha配置 +easycaptcha: + # 验证码类型配置 查看 LoginProperties 类 + code-type: arithmetic \ No newline at end of file diff --git a/target/classes/com/ms/reggie/controller/UserController.class b/target/classes/com/ms/reggie/controller/UserController.class index 4b4fdd3..21de446 100644 Binary files a/target/classes/com/ms/reggie/controller/UserController.class and b/target/classes/com/ms/reggie/controller/UserController.class differ diff --git a/target/classes/com/ms/reggie/filter/LoginCheckFilter.class b/target/classes/com/ms/reggie/filter/LoginCheckFilter.class index 79695ed..8153705 100644 Binary files a/target/classes/com/ms/reggie/filter/LoginCheckFilter.class and b/target/classes/com/ms/reggie/filter/LoginCheckFilter.class differ