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