feat: 图片旋转验证
This commit is contained in:
@@ -23,7 +23,6 @@ public class SmsInitConfig {
|
||||
List<SchisandraSmsConfigBO> SchisandraSmsConfigBOs= schisandraSmsConfigDomainService.queryAll();
|
||||
List<SchisandraSmsConfigDTO> schisandraSmsConfigDTOS = SchisandraSmsConfigDTOConvert.INSTANCE.convertBOToDTOList(SchisandraSmsConfigBOs);
|
||||
for (SchisandraSmsConfigDTO schisandraSmsConfig : schisandraSmsConfigDTOS){
|
||||
System.out.println(schisandraSmsConfig.toString());
|
||||
if (schisandraSmsConfig!=null){
|
||||
// 创建SmsBlend 短信实例
|
||||
SmsFactory.createSmsBlend(smsReadConfig);
|
||||
|
@@ -2,6 +2,12 @@ package com.schisandra.auth.application.controller;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
|
||||
import com.schisandra.auth.common.entity.CaptchaResult;
|
||||
import com.schisandra.auth.common.entity.Result;
|
||||
import com.schisandra.auth.common.redis.RedisUtil;
|
||||
import com.schisandra.auth.common.utils.AESUtils;
|
||||
import com.schisandra.auth.common.utils.RotateImageUtils;
|
||||
import com.schisandra.auth.common.utils.SmsCodeUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -11,97 +17,87 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/ReactRotateCaptcha/")
|
||||
@Slf4j
|
||||
public class ReactRotateCaptchaController {
|
||||
@PostMapping (value = "get", produces = MediaType.IMAGE_PNG_VALUE)
|
||||
public ResponseEntity<String> get(){
|
||||
//前端可以直接根据URL:/image/{图片id} 来获取图片 注意:资源文件ID最好进行加密和设置有效期
|
||||
// 在实际开发中 一般先通过图片id查看数据库有没有这条记录
|
||||
|
||||
String imageFilePath = "D:\\java_project\\schisandra-cloud-storage\\schisandra-cloud-storage-auth\\schisandra-cloud-storage-auth-application\\schisandra-cloud-storage-auth-application-controller\\src\\main\\java\\com\\schisandra\\auth\\application\\image\\test1.png";
|
||||
File file = new File(imageFilePath);
|
||||
try {
|
||||
BufferedImage bufferedImage = ImageIO.read(file);
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
ImageIO.write(bufferedImage, "png", byteArrayOutputStream);
|
||||
byte[] imageBytes = byteArrayOutputStream.toByteArray(); // 读取图片数据的字节数组
|
||||
// 将图片字节数组转换为Base64编码的字符串
|
||||
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
|
||||
System.out.println(base64Image);
|
||||
// 创建包含Base64编码的响应体的ResponseEntity对象,并设置正确的媒体类型和内容长度
|
||||
return ResponseEntity.ok().contentType(MediaType.IMAGE_PNG)
|
||||
.body(base64Image);
|
||||
}catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return ResponseEntity.ok().body(null);
|
||||
}
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
public final String authRotateCaptchaPrefix = "auth.RotateCaptcha";
|
||||
|
||||
/**
|
||||
* 请求图片地址, 返回的结果进行base64编码
|
||||
* @param imgUrl 图片地址
|
||||
* @return
|
||||
* @description:获取图片
|
||||
* @param: []
|
||||
* @return: java.lang.String
|
||||
* @author zlg
|
||||
* @date: 2024/5/10 16:28
|
||||
*/
|
||||
// public static String requestUrlToBase64(String imgUrl) {
|
||||
// //读取图片字节数组
|
||||
// byte[] data = null;
|
||||
// try {
|
||||
// InputStream in = new FileInputStream(imgUrl);
|
||||
//// System.out.println("文件大小(字节)=" + in.available());
|
||||
// data = new byte[in.available()];
|
||||
// in.read(data);
|
||||
// in.close();
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// //对字节数组进行Base64编码,得到Base64编码的字符串
|
||||
// return new String(Base64.encodeBase64(data));
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public static File convertBase64ToFile(String fileBase64String, String filePath, String fileName) {
|
||||
// BufferedOutputStream bos = null;
|
||||
// FileOutputStream fos = null;
|
||||
// File file = null;
|
||||
// try {
|
||||
// File dir = new File(filePath);
|
||||
// //判断文件目录是否存在
|
||||
// if (!dir.exists() && dir.isDirectory()) {
|
||||
// dir.mkdirs();
|
||||
// }
|
||||
// byte[] bfile = Base64.decodeBase64(fileBase64String);
|
||||
// file = new File(filePath + File.separator + fileName);
|
||||
// fos = new FileOutputStream(file);
|
||||
// bos = new BufferedOutputStream(fos);
|
||||
// bos.write(bfile);
|
||||
// return file;
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// } finally {
|
||||
// if (bos != null) {
|
||||
// try {
|
||||
// bos.close();
|
||||
// } catch (IOException e1) {
|
||||
// e1.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// if (fos != null) {
|
||||
// try {
|
||||
// fos.close();
|
||||
// } catch (IOException e1) {
|
||||
// e1.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
@PostMapping("get")
|
||||
public CaptchaResult get() throws Exception {
|
||||
HashMap<String,String> map = new HashMap<>();
|
||||
RotateImageUtils rotateImageUtils = new RotateImageUtils();
|
||||
|
||||
InputStream inputStream= ReactRotateCaptchaController.class.getClassLoader().getResourceAsStream("image/test1.jpg");
|
||||
BufferedImage image = ImageIO.read(inputStream);
|
||||
Random random = new Random();
|
||||
double randomNumber = random.nextInt(280) + 40;
|
||||
String key = AESUtils.getKey();
|
||||
String token = AESUtils.encrypt(String.valueOf(randomNumber), key);
|
||||
String prefix = redisUtil.buildKey(authRotateCaptchaPrefix, token);
|
||||
redisUtil.setNx(prefix, String.valueOf(randomNumber), 60L, TimeUnit.SECONDS);
|
||||
try {
|
||||
BufferedImage image1 = rotateImageUtils.rotateImage(image, randomNumber, Color.black);
|
||||
map.put("token",token);
|
||||
map.put("str", RotateImageUtils.BufferedImageToBase64(image1));
|
||||
return CaptchaResult.ok(map);
|
||||
} catch (Exception e) {
|
||||
return CaptchaResult.fail();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description: 验证图片
|
||||
* @param: [token, num]
|
||||
* @return: com.schisandra.auth.common.entity.Result
|
||||
* @author zlg
|
||||
* @date: 2024/5/10 17:25
|
||||
*/
|
||||
@PostMapping("verfiy")
|
||||
public CaptchaResult verfiy(String token, Double num) {
|
||||
if (num == null && token == null) {
|
||||
return CaptchaResult.fail();
|
||||
}
|
||||
String prefix = redisUtil.buildKey(authRotateCaptchaPrefix, token);
|
||||
if (redisUtil.exist(prefix)) {
|
||||
double realNum = Double.parseDouble(redisUtil.get(prefix));
|
||||
if (Math.abs(realNum - num) / realNum < 0.05) {
|
||||
redisUtil.del(prefix);
|
||||
return CaptchaResult.ok();
|
||||
} else {
|
||||
return CaptchaResult.fail();
|
||||
}
|
||||
} else {
|
||||
return CaptchaResult.fail();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import cn.hutool.json.JSONUtil;
|
||||
import com.xkcoding.justauth.AuthRequestFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
@@ -92,9 +92,10 @@
|
||||
<dependency>
|
||||
<groupId>org.dromara.sms4j</groupId>
|
||||
<artifactId>sms4j-spring-boot-starter</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<version> 3.2.1 </version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara.sms4j</groupId>
|
||||
<artifactId>sms4j-Email-core</artifactId>
|
||||
@@ -108,12 +109,6 @@
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- lombok插件 -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
|
||||
<dependency>
|
||||
@@ -122,12 +117,6 @@
|
||||
<version>5.3.8</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>29.0-jre</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.studio</groupId>
|
||||
|
@@ -0,0 +1,46 @@
|
||||
package com.schisandra.auth.common.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CaptchaResult<T> {
|
||||
|
||||
private Integer code;
|
||||
|
||||
private String msg;
|
||||
|
||||
private T data;
|
||||
|
||||
public static CaptchaResult ok() {
|
||||
CaptchaResult result = new CaptchaResult();
|
||||
|
||||
result.setCode(0);
|
||||
result.setMsg("Success");
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> CaptchaResult ok(T data) {
|
||||
CaptchaResult result = new CaptchaResult();
|
||||
|
||||
result.setCode(0);
|
||||
result.setMsg("Success");
|
||||
result.setData(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static CaptchaResult fail() {
|
||||
CaptchaResult result = new CaptchaResult();
|
||||
|
||||
result.setCode(1);
|
||||
result.setMsg("Fail");
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> CaptchaResult fail(T data) {
|
||||
CaptchaResult result = new CaptchaResult();
|
||||
result.setCode(1);
|
||||
result.setMsg("Fail");
|
||||
result.setData(data);
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -0,0 +1,177 @@
|
||||
package com.schisandra.auth.common.utils;
|
||||
|
||||
import sun.misc.BASE64Decoder;
|
||||
import sun.misc.BASE64Encoder;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class RotateImageUtils {
|
||||
|
||||
public static Color bgColor = new Color(255, 255, 255);
|
||||
|
||||
|
||||
/**
|
||||
* @description: 压缩图片并将图片转换成base64
|
||||
* @param: [bufferedImage]
|
||||
* @return: java.lang.String
|
||||
* @author zlg
|
||||
* @date: 2024/5/9 13:13
|
||||
*/
|
||||
public static String BufferedImageToBase64(BufferedImage bufferedImage) throws IOException {
|
||||
int targetWidth = 400;
|
||||
int targetHeight = 400;
|
||||
// 获取原始图片的尺寸
|
||||
int originalWidth = bufferedImage.getWidth();
|
||||
int originalHeight = bufferedImage.getHeight();
|
||||
// 创建一个新的 BufferedImage,用于存放处理后的图片
|
||||
BufferedImage outputImage = new BufferedImage(targetWidth, targetHeight, bufferedImage.getType());
|
||||
// 创建一个 Graphics2D 对象,用于绘制新图片
|
||||
Graphics2D graphics = outputImage.createGraphics();
|
||||
// 如果原始图片尺寸大于目标尺寸,则进行压缩
|
||||
if (originalWidth > targetWidth || originalHeight > targetHeight) {
|
||||
Image scaledImage = bufferedImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_SMOOTH);
|
||||
graphics.drawImage(scaledImage, 0, 0, null);
|
||||
}
|
||||
graphics.dispose();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流
|
||||
ImageIO.write(outputImage, "png", baos);//写入流中
|
||||
byte[] bytes = baos.toByteArray();//转换成字节
|
||||
BASE64Encoder encoder = new BASE64Encoder();
|
||||
String png_base64 = encoder.encodeBuffer(bytes).trim();//转换成base64串
|
||||
png_base64 = png_base64.replaceAll("\n", "").replaceAll("\r", "");//删除 \r\n
|
||||
return "data:image/jpg;base64," + png_base64;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 将base64转换成图片
|
||||
* @param: [base64]
|
||||
* @return: java.awt.image.BufferedImage
|
||||
* @author zlg
|
||||
* @date: 2024/5/9 13:14
|
||||
*/
|
||||
public static BufferedImage base64ToBufferedImage(String base64) {
|
||||
BASE64Decoder decoder = new sun.misc.BASE64Decoder();
|
||||
try {
|
||||
byte[] bytes1 = decoder.decodeBuffer(base64);
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes1);
|
||||
return ImageIO.read(bais);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 获取旋转后的图片
|
||||
* @param: [image, theta, backgroundColor]
|
||||
* @return: java.awt.image.BufferedImage
|
||||
* @author zlg
|
||||
* @date: 2024/5/9 13:14
|
||||
*/
|
||||
public BufferedImage rotateImage(BufferedImage image, double theta, Color backgroundColor) {
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
double angle = theta * Math.PI / 180; // 度转弧度
|
||||
double[] xCoords = getX(width / 2, height / 2, angle);
|
||||
double[] yCoords = getY(width / 2, height / 2, angle);
|
||||
int WIDTH = (int) (xCoords[3] - xCoords[0]);
|
||||
int HEIGHT = (int) (yCoords[3] - yCoords[0]);
|
||||
BufferedImage resultImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
|
||||
for (int i = 0; i < WIDTH; i++) {
|
||||
for (int j = 0; j < HEIGHT; j++) {
|
||||
int x = i - WIDTH / 2;
|
||||
int y = HEIGHT / 2 - j;
|
||||
double radius = Math.sqrt(x * x + y * y);
|
||||
double angle1;
|
||||
if (y > 0) {
|
||||
angle1 = Math.acos(x / radius);
|
||||
} else {
|
||||
angle1 = 2 * Math.PI - Math.acos(x / radius);
|
||||
}
|
||||
x = (int) Math.round(radius * Math.cos(angle1 - angle));
|
||||
y = (int) Math.round(radius * Math.sin(angle1 - angle));
|
||||
if (x < (width / 2) & x > -(width / 2) & y < (height / 2) & y > -(height / 2)) {
|
||||
int rgb = image.getRGB((int) Math.round(x + width / 2), (int) Math.round(height / 2 - y));
|
||||
resultImage.setRGB(i, j, rgb);
|
||||
} else {
|
||||
resultImage.setRGB(i, j, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultImage;
|
||||
}
|
||||
|
||||
// 获取四个角点旋转后Y方向坐标
|
||||
private double[] getY(int i, int j, double angle) {
|
||||
double results[] = new double[4];
|
||||
double radius = Math.sqrt(i * i + j * j);
|
||||
double angle1 = Math.asin(j / radius);
|
||||
results[0] = radius * Math.sin(angle1 + angle);
|
||||
results[1] = radius * Math.sin(Math.PI - angle1 + angle);
|
||||
results[2] = -results[0];
|
||||
results[3] = -results[1];
|
||||
Arrays.sort(results);
|
||||
return results;
|
||||
}
|
||||
|
||||
// 获取四个角点旋转后X方向坐标
|
||||
private double[] getX(int i, int j, double angle) {
|
||||
double results[] = new double[4];
|
||||
double radius = Math.sqrt(i * i + j * j);
|
||||
double angle1 = Math.acos(i / radius);
|
||||
results[0] = radius * Math.cos(angle1 + angle);
|
||||
results[1] = radius * Math.cos(Math.PI - angle1 + angle);
|
||||
results[2] = -results[0];
|
||||
results[3] = -results[1];
|
||||
Arrays.sort(results);
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 获取旋转后的图片
|
||||
* @param: [image]
|
||||
* @return: java.awt.image.BufferedImage
|
||||
* @author zlg
|
||||
* @date: 2024/5/9 13:14
|
||||
*/
|
||||
public BufferedImage writeCyclePic(BufferedImage image) {
|
||||
BufferedImage newImage = new BufferedImage(350, 350, BufferedImage.TYPE_INT_BGR);
|
||||
try {
|
||||
int width = image.getWidth();
|
||||
int heigth = image.getHeight();
|
||||
double x0 = width / 2;
|
||||
double y0 = heigth / 2;
|
||||
int woffset = (width - 350) / 2;
|
||||
int hoffset = (heigth - 350) / 2;
|
||||
for (int i = woffset; i < 350 + woffset; i++) {
|
||||
for (int j = hoffset; j < 350 + hoffset; j++) {
|
||||
double r = Math.sqrt(Math.pow(Math.abs(i - x0), 2.0) + Math.pow(Math.abs(j - y0), 2.0));
|
||||
if (r > (x0 - woffset)) {
|
||||
newImage.setRGB(i - woffset, j - hoffset, -1);
|
||||
} else {
|
||||
newImage.setRGB(i - woffset, j - hoffset, image.getRGB(i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
return newImage;
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@@ -37,7 +37,6 @@
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.schisandra</groupId>
|
||||
<artifactId>schisandra-cloud-storage-auth-application-controller</artifactId>
|
||||
|
Reference in New Issue
Block a user