图形滑动验证码JAVA实现【前后端结合】

图形滑动验证码JAVA实现【前后端结合】⼀、为什么要验证码?
防暴⼒破解的课题⼀直是信息安全的重点,漏洞攻击更是开发者的噩梦。。。。
如果没有经历过这个噩梦,请感受⼀下被信安部门⽀配的恐惧。(⼀⼤堆漏洞给扫出来,您修代码吧)
⼆、怎么实现的?
前端:HTML+JS+CSS  开源组件:Layui
后端:Java  后端框架:SpringBoot
思路:
后端随机读取⼀张图⽚,利⽤算法随机“抠图”,返回base64码值到前端
押花材料前端读取到base64,转码⽣成图⽚,底部搭配上“滑块”进⾏拼图匹配
后端取到匹配的误差值,计算,返回前端验证,是否成功
⼿机模式看看效果:
三、代码⽰例
1、Java⼯具类:class VerifyImageUtil
⽤于⽣成滑动验证码的两个要素
根据原图⽚裁剪出
裁剪块blockImage;
与裁剪后的原图targetImage
并返回左上⾓坐标(X,Y)
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Random;
public class VerifyImageUtil {
/**
电容笔制作
* 源⽂件宽度
*/
private static int ORI_WIDTH = 200;
/**
* 源⽂件⾼度
*/
射击标靶
private static int ORI_HEIGHT = 116;
/**
* 模板图宽度
*/
private static int CUT_WIDTH = 50;
/**
* 模板图⾼度
*/
private static int CUT_HEIGHT = 50;
/**
* 抠图凸起圆⼼
*/
private static int circleR = 5;
/
**
* 抠图内部矩形填充⼤⼩
*/
private static int RECTANGLE_PADDING = 8;
/**
* 抠图的边框宽度
*/
private static int SLIDER_IMG_OUT_PADDING = 1;
/**
* 根据传⼊的路径⽣成指定验证码图⽚
*
* @param filePath
* @return
* @throws IOException
*/
public static VerifyImage getVerifyImage(String filePath) throws IOException {
BufferedImage srcImage = ad(new File(filePath));
int locationX = CUT_WIDTH + new Random().Width() - CUT_WIDTH * 3);
int locationY = CUT_HEIGHT + new Random().Height() - CUT_HEIGHT) / 2;
BufferedImage markImage = new BufferedImage(CUT_WIDTH,CUT_HEIGHT,BufferedImage.TYPE_4BYTE_ABGR);
int[][] data = getBlockData();
cutImgByTemplate(srcImage, markImage, data, locationX, locationY);
return new VerifyImage(getImageBASE64(srcImage),getImageBASE64(markImage),locationX,Width(),Height());    }
/**
* ⽣成随机滑块形状
* <p>
* 1 滑块像素
* 2 阴影像素
* @return int[][]
新型电子产品*/
private static int[][] getBlockData() {
int[][] data = new int[CUT_WIDTH][CUT_HEIGHT];
Random random = new Random();
//(x-a)²+(y-b)²=r²
//x中⼼位置左右5像素随机
double x1 = RECTANGLE_PADDING + (CUT_WIDTH - 2 * RECTANGLE_PADDING) / 2.0 - 5 + Int(10);
//y 矩形上边界半径-1像素移动
double y1_top = RECTANGLE_PADDING - Int(3);
double y1_bottom = CUT_HEIGHT - RECTANGLE_PADDING + Int(3);
double y1 = Int(2) == 1 ? y1_top : y1_bottom;
double x2_right = CUT_WIDTH - RECTANGLE_PADDING - circleR + Int(2 * circleR - 4);
double x2_left = RECTANGLE_PADDING + circleR - 2 - Int(2 * circleR - 4);
double x2 = Int(2) == 1 ? x2_right : x2_left;
double y2 = RECTANGLE_PADDING + (CUT_HEIGHT - 2 * RECTANGLE_PADDING) / 2.0 - 4 + Int(10);
double po = Math.pow(circleR, 2);
for (int i = 0; i < CUT_WIDTH; i++) {
for (int j = 0; j < CUT_HEIGHT; j++) {
//矩形区域
boolean fill;
if ((i >= RECTANGLE_PADDING && i < CUT_WIDTH - RECTANGLE_PADDING)
&& (j >= RECTANGLE_PADDING && j < CUT_HEIGHT - RECTANGLE_PADDING)) {
data[i][j] = 1;
fill = true;
} else {
data[i][j] = 0;
fill = false;
}
//凸出区域
double d3 = Math.pow(i - x1, 2) + Math.pow(j - y1, 2);
if (d3 < po) {
data[i][j] = 1;
} else {
if (!fill) {
data[i][j] = 0;
}
}
//凹进区域
double d4 = Math.pow(i - x2, 2) + Math.pow(j - y2, 2);
if (d4 < po) {
data[i][j] = 0;
}
}
}
//边界阴影
for (int i = 0; i < CUT_WIDTH; i++) {
for (int j = 0; j < CUT_HEIGHT; j++) {
/
/四个正⽅形边⾓处理
for (int k = 1; k <= SLIDER_IMG_OUT_PADDING; k++) {
//左上、右上
if (i >= RECTANGLE_PADDING - k && i < RECTANGLE_PADDING
&& ((j >= RECTANGLE_PADDING - k && j < RECTANGLE_PADDING)
|| (j >= CUT_HEIGHT - RECTANGLE_PADDING - k && j < CUT_HEIGHT - RECTANGLE_PADDING +1))) {                        data[i][j] = 2;
}
//左下、右下
if (i >= CUT_WIDTH - RECTANGLE_PADDING + k - 1 && i < CUT_WIDTH - RECTANGLE_PADDING + 1) {
if (((j >= RECTANGLE_PADDING - n && j < RECTANGLE_PADDING)
|| (j >= CUT_HEIGHT - RECTANGLE_PADDING - n && j <= CUT_HEIGHT - RECTANGLE_PADDING ))) {
data[i][j] = 2;
}
}
}
}
if (data[i][j] == 1 && j - SLIDER_IMG_OUT_PADDING > 0 && data[i][j - SLIDER_IMG_OUT_PADDING] == 0) {
data[i][j - SLIDER_IMG_OUT_PADDING] = 2;
}
if (data[i][j] == 1 && j + SLIDER_IMG_OUT_PADDING > 0 && j + SLIDER_IMG_OUT_PADDING < C
UT_HEIGHT && data[i][j + SLIDER_IMG_OUT_PAD                    data[i][j + SLIDER_IMG_OUT_PADDING] = 2;
}
if (data[i][j] == 1 && i - SLIDER_IMG_OUT_PADDING > 0 && data[i - SLIDER_IMG_OUT_PADDING][j] == 0) {
data[i - SLIDER_IMG_OUT_PADDING][j] = 2;
}
if (data[i][j] == 1 && i + SLIDER_IMG_OUT_PADDING > 0 && i + SLIDER_IMG_OUT_PADDING < CUT_WIDTH && data[i + SLIDER_IMG_OUT_PADDIN                    data[i + SLIDER_IMG_OUT_PADDING][j] = 2;
}
}
}
return data;
}
/**
* 裁剪区块
* 根据⽣成的滑块形状,对原图和裁剪块进⾏变⾊处理
* @param oriImage    原图
* @param targetImage 裁剪图
* @param blockImage  滑块
* @param x          裁剪点x
* @param y          裁剪点y
*/
private static void cutImgByTemplate(BufferedImage oriImage, BufferedImage targetImage, int[][] blockImage, int x, int y) {
for (int i = 0; i < CUT_WIDTH; i++) {
for (int j = 0; j < CUT_HEIGHT; j++) {
int _x = x + i;
int _y = y + j;
int rgbFlg = blockImage[i][j];
int rgb_ori = RGB(_x, _y);
加热搅拌// 原图中对应位置变⾊处理
if (rgbFlg == 1) {
//抠图上复制对应颜⾊值
targetImage.setRGB(i,j, rgb_ori);
//原图对应位置颜⾊变化
oriImage.setRGB(_x, _y, Color.RGB());
} else if (rgbFlg == 2) {
targetImage.setRGB(i, j, RGB());
oriImage.setRGB(_x, _y, RGB());
}else if(rgbFlg == 0){
//int alpha = 0;
targetImage.setRGB(i, j, rgb_ori & 0x00ffffff);
}
}
}
}
/**
* 随机获取⼀张图⽚对象
* @param path
* @return
*/
public static BufferedImage getRandomImage(String path) throws IOException {
File files = new File(path);
File[] fileList = files.listFiles();
List<String> fileNameList = new ArrayList<>();
if (fileList!=null && fileList.length!=0){
for (File tempFile:fileList){
if (tempFile.isFile() && Name().endsWith(".jpg")){
fileNameList.AbsolutePath().trim());
}
}
}
Random random = new Random();消弧消谐柜
File imageFile = new (Int(fileNameList.size())));
ad(imageFile);
}
/**
* 将IMG输出为⽂件
* @param image
* @param file
* @throws Exception
*/
public static void writeImg(BufferedImage image, String file) throws Exception {
byte[] imagedata = null;
ByteArrayOutputStream bao=new ByteArrayOutputStream();
ImageIO.write(image,"png",bao);
imagedata = ByteArray();
FileOutputStream out = new FileOutputStream(new File(file));
out.write(imagedata);
out.close();
}
/**
* 将图⽚转换为BASE64
* @param image
* @return
* @throws IOException
*/
public static String getImageBASE64(BufferedImage image) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(image,"png",out);
//转成byte数组
byte[] bytes = ByteArray();
BASE64Encoder encoder = new BASE64Encoder();
//⽣成BASE64编码
//String showBase64 = de(bytes);
String showBase64 =  Encoder().encodeToString(bytes);
//        System.out.println("showBase64:\n"+showBase64+"\n");
return showBase64;
}
/**
* 将BASE64字符串转换为图⽚
* @param base64String
* @return
*/
public static BufferedImage base64StringToImage(String base64String) {
try {
BASE64Decoder decoder=new BASE64Decoder();
byte[] bytes1 = decoder.decodeBuffer(base64String);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes1);            ad(byteArrayInputStream);

本文发布于:2024-09-23 02:18:29,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/1/219760.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:原图   验证码   返回   对应   噩梦   位置
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议