目录
前后端代码:
java滚动验证码-前端和后端完整版_outdata的博客-CSDN博客_java图片滚动验证
图形滑动验证码JAVA实现【前后端结合】_LeonardoZzzz的博客-CSDN博客_滑动验证码完成安全验证
一、配置文件
#验证码图片地址,需要改成你本地的地址
#路径调试的时候,配成全路径,不要配成相对路径。相对路径打成jar包的时候,读取不到文件
#这是前后端分离方式的调用,路径应该由服务器来配置,这里需要手动配置路径。其它方式读取文件,可自行调整CaptchaServiceImpl实现类中selectSlideVerificationCode方法文件读取方式
captcha:
slide-verification-code:
path:
template-image: "/static/templates"
origin-image: "/static/targets"
二、图片
三、代码实现
import com.aliyun.oss.ServiceException;
import com.lgh.code.common.model.base.Result;
import com.lgh.universal.service.ImageVerificationService;
import com.lgh.universal.util.ImageVerificationCheckDTO;
import com.lgh.universal.util.ImageVerificationVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
/**
* @author: cyl
* @date: 2022/3/22 16:17
*/
@RestController
@RequestMapping(value = "/image/verification")
@Api(tags = "图片滑动验证码")
@Slf4j
@RequiredArgsConstructor
public class ImageVerificationController {
private final ImageVerificationService service;
@GetMapping("/get")
@ApiOperation(value = "获取验证码")
public Result getVerificationImage() {
ImageVerificationVO vo;
try {
vo = service.selectSlideVerificationCode();
} catch (ServiceException e) {
return Result.fail(e.getMessage());
}
return Result.ok(vo);
}
@ApiOperation(value = "校验验证码")
@PostMapping("/check")
public Result checkVerificationResult(@Valid @RequestBody ImageVerificationCheckDTO dto) {
return service.checkVerificationResult(dto.getX(), dto.getY());
}
}
import com.aliyun.oss.ServiceException;
import com.lgh.code.common.constant.RedisConstants;
import com.lgh.code.common.constant.TokenTimeConstants;
import com.lgh.code.common.context.SecurityContextHolder;
import com.lgh.code.common.model.base.Result;
import com.lgh.code.redis.service.RedisService;
import com.lgh.universal.util.ImageRead;
import com.lgh.universal.util.ImageVerificationUtil;
import com.lgh.universal.util.ImageVerificationVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Service;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.util.Random;
/**
* 图片滑动验证码 业务实现类
* @author: cyl
* @date: 2022/3/22 16:28
*/
@Service
@Slf4j
@RequiredArgsConstructor
public class ImageVerificationService {
private final RedisService redisService;
/**
* 源图路径前缀
*/
@Value("${captcha.slide-verification-code.path.origin-image:classpath:static/targets}")
private String verificationImagePathPrefix;
/**
* 模板图路径前缀
*/
@Value("${captcha.slide-verification-code.path.template-image:classpath:static/templates}")
private String templateImagePathPrefix;
/**
* 获取滑动验证码
*
* @return 滑动验证码
*/
public ImageVerificationVO selectSlideVerificationCode() throws ServiceException {
ImageVerificationVO vo;
try {
// 随机取得原图文件夹中一张图片
ImageRead originImageRead = readTargetImage();
// 获取模板图片文件
ImageRead templateImageRead = readTemplateImage(templateImagePathPrefix.concat("/template.png"));
// 获取描边图片文件
ImageRead borderImageRead = readBorderImageFile(templateImagePathPrefix.concat("/border.png"));
// 获取原图文件类型
String originImageFileType = originImageRead.getFileExtension();
// 获取模板图文件类型
String templateImageFileType = templateImageRead.getFileExtension();
// 获取边框图文件类型
String borderImageFileType = borderImageRead.getFileExtension();
// 读取原图
BufferedImage verificationImage = originImageRead.getImage();
// 读取模板图
BufferedImage readTemplateImage = templateImageRead.getImage();
// 读取描边图片
BufferedImage borderImage = borderImageRead.getImage();
// 获取原图感兴趣区域坐标
vo = ImageVerificationUtil.generateCutoutCoordinates(verificationImage, readTemplateImage);
int y = vo.getY();
redisService.set(RedisConstants.IMAGE_VERIFICATION + SecurityContextHolder.getUserId(), vo, TokenTimeConstants.MILLIS_MINUTES);
// 根据原图生成遮罩图和切块图
vo = ImageVerificationUtil.pictureTemplateCutout(verificationImage, originImageRead.getInputStream(), originImageFileType, readTemplateImage, templateImageFileType, vo.getX(), vo.getY());
// 剪切图描边
vo = ImageVerificationUtil.cutoutImageEdge(vo, borderImage, borderImageFileType);
vo.setY(y);
// =============================================
// 输出图片
// HttpServletResponse response = getResponse();
// response.setContentType("image/jpeg");
// ServletOutputStream outputStream = response.getOutputStream();
// outputStream.write(oriCopyImages);
// BufferedImage bufferedImage = ImageIO.read(originImageFile);
// ImageIO.write(bufferedImage, originImageType, outputStream);
// outputStream.flush();
// =================================================
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new ServiceException(e.getMessage());
}
return vo;
}
/**
* 读取目标图
*
* @return
* @throws ServiceException
*/
public ImageRead readTargetImage() throws ServiceException {
ImageRead imageRead = null;
try {
Random random = new Random(System.currentTimeMillis());
log.info("读取目标图: {}", verificationImagePathPrefix);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources(verificationImagePathPrefix.concat("/*"));
if (resources == null) {
throw new RuntimeException("not found target image");
}
int i = random.nextInt(resources.length);
imageRead = new ImageRead();
imageRead.setImage(ImageIO.read(resources[i].getInputStream()));
String extension = resources[i].getFilename().substring(resources[i].getFilename().lastIndexOf(".") + 1);
imageRead.setInputStream(resources[i].getInputStream());
imageRead.setFileExtension(extension);
log.info("读取目标图: 完成");
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new ServiceException(e.getMessage());
}
return imageRead;
}
/**
* 读取模板图
*
* @param path
* @return
* @throws ServiceException
*/
public ImageRead readTemplateImage(String path) throws ServiceException {
ImageRead templateImageFile = null;
try {
if (templateImageFile != null) {
return templateImageFile;
}
templateImageFile = new ImageRead();
log.info("读取模板图:{}", path);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource resource = resolver.getResource(path);
if (resource == null) {
throw new RuntimeException("not found template image");
}
templateImageFile.setImage(ImageIO.read(resource.getInputStream()));
String extension = resource.getFilename().substring(resource.getFilename().lastIndexOf(".") + 1);
templateImageFile.setInputStream(resource.getInputStream());
templateImageFile.setFileExtension(extension);
log.info("读取模板图:完成");
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new ServiceException(e.getMessage());
}
return templateImageFile;
}
/**
* 读取边框图
*
* @param path
* @return
* @throws ServiceException
*/
public ImageRead readBorderImageFile(String path) throws ServiceException {
ImageRead borderImageFile = null;
try {
if (borderImageFile != null) {
return borderImageFile;
}
borderImageFile = new ImageRead();
log.info("读取边框图:{}", path);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource resource = resolver.getResource(path);
if (resource == null) {
throw new RuntimeException("not found template image");
}
borderImageFile.setImage(ImageIO.read(resource.getInputStream()));
String extension = resource.getFilename().substring(resource.getFilename().lastIndexOf(".") + 1);
borderImageFile.setInputStream(resource.getInputStream());
borderImageFile.setFileExtension(extension);
log.info("读取边框图:完成");
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new ServiceException(e.getMessage());
}
return borderImageFile;
}
/**
* 滑动验证码验证方法
*
* @param x x轴坐标
* @param y y轴坐标
* @return 滑动验证码验证状态
* @throws ServiceException 验证滑动验证码异常
*/
public Result checkVerificationResult(String x, String y) throws ServiceException {
int threshold = 5;
try {
ImageVerificationVO vo = (ImageVerificationVO) redisService.get(RedisConstants.IMAGE_VERIFICATION + SecurityContextHolder.getUserId());
if (vo != null) {
if ((Math.abs(Integer.parseInt(x) - vo.getX()) <= threshold) && y.equals(String.valueOf(vo.getY()))) {
redisService.delete(RedisConstants.IMAGE_VERIFICATION + SecurityContextHolder.getUserId());
return Result.ok();
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new ServiceException(e.getMessage());
}
return Result.fail("图片滑动验证失败");
}
}