package com.iplatform.base.controller; import com.iplatform.base.ArgumentsConstants; import com.iplatform.base.Constants; import com.iplatform.base.SystemController; import com.iplatform.base.captcha.BlockPuzzleCaptchaProvider; import com.iplatform.base.captcha.JigsawCaptchaProvider; import com.iplatform.base.captcha.JigsawResult; import com.walker.infrastructure.utils.Base64; import com.walker.infrastructure.utils.StringUtils; import com.walker.web.CaptchaProvider; import com.walker.web.CaptchaResult; import com.walker.web.ResponseValue; import com.walker.web.util.IdUtils; 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.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.imageio.ImageIO; import java.io.IOException; import java.util.HashMap; import java.util.Map; /** * 验证码生成接口,所有其他类型验证码生成器可以实现:CaptchaProvider,分离各种区别。 * @author 时克英 * @date 2022-11-07 */ @RestController public class CaptchaController extends SystemController { private CaptchaProvider imageCaptchaProvider; // private CaptchaProvider smsCaptchaProvider; // 2023-04-06 拼图验证码提供者 private JigsawCaptchaProvider jigsawCaptchaProvider; private BlockPuzzleCaptchaProvider blockPuzzleCaptchaProvider; // 简单验证码类型: char, math private String defaultCaptchaType = "math"; @Autowired public CaptchaController(CaptchaProvider imageCaptchaProvider // , CaptchaProvider smsCaptchaProvider // , CacheProvider captchaCacheProvider , JigsawCaptchaProvider jigsawCaptchaProvider, BlockPuzzleCaptchaProvider blockPuzzleCaptchaProvider){ this.imageCaptchaProvider = imageCaptchaProvider; // this.smsCaptchaProvider = smsCaptchaProvider; // this.captchaCacheProvider = captchaCacheProvider; this.jigsawCaptchaProvider = jigsawCaptchaProvider; this.blockPuzzleCaptchaProvider = blockPuzzleCaptchaProvider; } @RequestMapping("/captcha/jigsaw/mobile") public ResponseValue generateJigsawMobileCaptcha(){ String uuid = IdUtils.simpleUUID(); Map data = new HashMap<>(4); data.put("uuid", uuid); String verifyKey = Constants.CAPTCHA_CODE_PREFIX + uuid; JigsawResult captchaResult = (JigsawResult)this.blockPuzzleCaptchaProvider.generateCaptcha(null); if(captchaResult == null || captchaResult.getX() == 0){ return ResponseValue.error("拼图验证码生成错误, null"); } // 写入验证码 x位置 到缓存中 this.getCaptchaCacheProvider().putCacheData(verifyKey, String.valueOf(captchaResult.getX()), 60); logger.debug("写入拼图验证位置,x = {}", captchaResult.getX()); data.put("y", captchaResult.getY()); data.put("slider", captchaResult.getImageBlockBase64()); data.put("bg", captchaResult.getImageSourceBase64()); // data.put("captchaEnabled", true); return ResponseValue.success(data); } /** * 验证拼图位置 * @param token 传入的uuid * @param x 横坐标位置 * @return * @date 2023-04-07 */ @PostMapping("/captcha/jigsaw_validate") public ResponseValue validateJigsaw(String token, String x){ if(StringUtils.isEmpty(token) || StringUtils.isEmpty(x)){ return ResponseValue.error("未接收到验证输入信息!"); } // String verifyKey = Constants.CAPTCHA_CODE_PREFIX + token; // String xString = this.captchaCacheProvider.getCacheData(verifyKey); // if(StringUtils.isEmpty(xString)){ // throw new IllegalStateException("拼图验证信息已失效!"); // } CaptchaResult captchaResult = new CaptchaResult(); captchaResult.setUuid(token); captchaResult.setCode(x); Map data = new HashMap<>(4); boolean success = this.jigsawCaptchaProvider.validateCaptcha(captchaResult); if(!success){ // 验证失败 data.put("verify", "-1"); return ResponseValue.success(data); } data.put("verify", "1"); data.put("x", x); data.put("uuid", token); // uuid也要返回界面 return ResponseValue.success(data); } /** * 获取拼图验证码信息。 * @return * @date 2023-04-06 */ @RequestMapping("/captcha/jigsaw") public ResponseValue generateJigsawCaptcha(){ // SimpleKaptchaProvider provider = null; boolean captchaEnabled = this.getArgumentVariable(ArgumentsConstants.KEY_SECURITY_CAPTCHA_ENABLED).getBooleanValue(); String uuid = IdUtils.simpleUUID(); Map data = new HashMap<>(4); data.put("uuid", uuid); if(captchaEnabled){ String verifyKey = Constants.CAPTCHA_CODE_PREFIX + uuid; JigsawResult captchaResult = (JigsawResult)this.jigsawCaptchaProvider.generateCaptcha(null); if(captchaResult == null || captchaResult.getX() == 0){ return ResponseValue.error("拼图验证码生成错误, null"); } // 写入验证码 x位置 到缓存中 this.getCaptchaCacheProvider().putCacheData(verifyKey, String.valueOf(captchaResult.getX()), 60); logger.debug("写入拼图验证位置,x = {}", captchaResult.getX()); data.put("y", captchaResult.getY()); data.put("slider", captchaResult.getImageBlockBase64()); data.put("bg", captchaResult.getImageSourceBase64()); data.put("captchaEnabled", true); return ResponseValue.success(data); } else { // 没有验证码方式 data.put("captchaEnabled", false); return ResponseValue.success(data); } } /** * 生成短信验证码,放入缓存。 * @param phoneNumber * @return * @date 2023-01-27 */ // @RequestMapping("/captchaSms") @RequestMapping("/captcha/sms") public ResponseValue generateSmsCaptcha(String phoneNumber){ if(StringUtils.isEmpty(phoneNumber)){ return ResponseValue.error("请输入手机号"); } /*String uuid = IdUtils.simpleUUID(); Map data = new HashMap<>(4); data.put("uuid", uuid); String verifyKey = Constants.CAPTCHA_CODE_PREFIX + uuid; CaptchaResult captchaResult = this.getSmsCaptchaProvider().generateCaptcha(phoneNumber); if(captchaResult == null){ return ResponseValue.error("短信验证码生成错误, null"); } // 写入验证码 key 和 code 到缓存中 this.getCaptchaCacheProvider().putCacheData(verifyKey, captchaResult.getCode(), 120); if(this.logger.isDebugEnabled()){ this.logger.debug("生成短信验证码:{}, uuid:{}", captchaResult.getCode(), uuid); }*/ try{ Map data = this.sendSmsCodeValidation(phoneNumber); return ResponseValue.success(data); } catch (Exception ex){ return ResponseValue.error(ex.getMessage()); } } /** * PC端登录,生成简单的图像验证码 * @return * @date 2022-10-11 */ // @GetMapping("/captchaImage") @GetMapping("/captcha/image") public ResponseValue generateImageCaptcha(){ // boolean captchaEnabled = VariableConstants.CAPTCHA_ENABLED; boolean captchaEnabled = this.getArgumentVariable(ArgumentsConstants.KEY_SECURITY_CAPTCHA_ENABLED).getBooleanValue(); String uuid = IdUtils.simpleUUID(); Map data = new HashMap<>(4); data.put("uuid", uuid); if(captchaEnabled){ String verifyKey = Constants.CAPTCHA_CODE_PREFIX + uuid; CaptchaResult captchaResult = this.imageCaptchaProvider.generateCaptcha(this.defaultCaptchaType); if(captchaResult == null){ return ResponseValue.error("验证码生成错误, null"); } // 写入验证码 key 和 code 到缓存中 this.getCaptchaCacheProvider().putCacheData(verifyKey, captchaResult.getCode(), 120); if(this.logger.isDebugEnabled()){ this.logger.debug("生成图像验证码:{}, uuid:{}", captchaResult.getCode(), uuid); } // 转换流信息写出 FastByteArrayOutputStream os = new FastByteArrayOutputStream(); try { ImageIO.write(captchaResult.getImage(), "jpg", os); data.put("img", new String(Base64.encode(os.toByteArray()), StringUtils.DEFAULT_CHARSET_UTF8)); // data.put("img", CaptchaUtils.encode(os.toByteArray())); data.put("captchaEnabled", true); return ResponseValue.success(data); } catch (IOException e) { return ResponseValue.error(e.getMessage()); } } else { // 没有验证码方式 data.put("captchaEnabled", false); return ResponseValue.success(data); } } /** * 在slider滑块验证,sms短信验证时,不需要实际验证码,仅返回uuid。 * @return * @date 2023-03-22 */ @GetMapping("/captcha/none") public ResponseValue generateCaptchaNone(){ String uuid = IdUtils.simpleUUID(); Map data = new HashMap<>(4); data.put("uuid", uuid); return ResponseValue.success(data); } }