feat: 短信验证码和滑动图片验证

This commit is contained in:
zlg
2024-04-27 15:00:03 +08:00
parent af12c239e5
commit 35e3cdef8a
5 changed files with 296 additions and 32 deletions

View File

@@ -0,0 +1,107 @@
package com.schisandra.auth.application.controller;
import cn.hutool.core.lang.Assert;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
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.awt.image.BufferedImage;
import java.io.*;
import java.util.Base64;
@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);
}
/**
* 请求图片地址, 返回的结果进行base64编码
* @param imgUrl 图片地址
* @return
*/
// 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;
// }
}

View File

@@ -0,0 +1,46 @@
package com.schisandra.auth.application.controller;
import com.schisandra.auth.common.utils.RedisUtils;
import com.schisandra.auth.common.utils.SmsCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.core.factory.SmsFactory;
import org.dromara.sms4j.provider.enumerate.SupplierType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.LinkedHashMap;
@RestController
@RequestMapping("/sms/")
@Slf4j
public class SmsController {
@Autowired
private RedisUtils redisUtils;
private final SmsBlend aliSms = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
@GetMapping("/send")
public SmsResponse send(String phone, String templateId) {
return aliSms.sendMessage(phone, templateId, new LinkedHashMap<>());
}
@GetMapping("/sendByTemplate")
public SmsResponse sendByTemplate(String phone) {
// SmsBlend smsBlend = SmsFactory.getSmsBlend("alibaba");
String code = SmsCodeUtils.generateValidateCode(4).toString();
// redisUtils.cacheValue( phone, code, 60);
SmsResponse smsResponse=aliSms.sendMessage(phone, code);
if (smsResponse.isSuccess()){
redisUtils.cacheValue( phone, code, 60);
return smsResponse;
}else {
return smsResponse;
}
}
}

View File

@@ -0,0 +1,86 @@
package com.schisandra.auth.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @author luft-mensch
*/
@Component
public class RedisUtils {
@Resource
private RedisTemplate<String,Object> redisTemplate;
private Logger logger = LoggerFactory.getLogger(this.getClass());
public boolean cacheValue(String key, Object value, long time) {
try {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
valueOperations.set(key, value);
if (time > 0) {
// 如果有设置超时时间的话
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Throwable e) {
logger.error("缓存[" + key + "]失败, value[" + value + "] " + e.getMessage());
}
return false;
}
public boolean cacheValue(String key, Object value) {
return cacheValue(key, value, -1);
}
public boolean containsKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Throwable e) {
logger.error("判断缓存是否存在时失败key[" + key + "]", "err[" + e.getMessage() + "]");
}
return false;
}
public Object getValue(String key) {
try {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
return valueOperations.get(key);
} catch (Throwable e) {
logger.error("获取缓存时失败key[" + key + "]", "err[" + e.getMessage() + "]");
}
return null;
}
public boolean removeValue(String key) {
try {
redisTemplate.delete(key);
return true;
} catch (Throwable e) {
logger.error("移除缓存时失败key[" + key + "]", "err[" + e.getMessage() + "]");
}
return false;
}
public boolean removeKeys(String pattern) {
try {
Set<String> keySet = redisTemplate.keys(pattern + "*");
redisTemplate.delete(keySet);
return true;
} catch (Throwable e) {
logger.error("移除key[" + pattern + "]前缀的缓存时失败", "err[" + e.getMessage() + "]");
}
return false;
}
}

View File

@@ -0,0 +1,32 @@
package com.schisandra.auth.common.utils;
import java.util.Random;
public class SmsCodeUtils {
public static Integer generateValidateCode(int length){
Integer code =null;
//长度为4
if(length == 4){
//生成随机数最大为9999
code = new Random().nextInt(9999);
if(code < 1000){
//保证随机数为4位数字
code = code + 1000;
}
//长度为6
}else if(length == 6){
//生成随机数最大为999999
code = new Random().nextInt(999999);
if(code < 100000){
//保证随机数为6位数字
code = code + 100000;
}
//其他情况
}else{
throw new RuntimeException("只能生成4位或6位数字验证码");
}
return code;
}
}

View File

@@ -70,37 +70,30 @@ sa-token:
is-log: true
token-prefix: schisandra
#sms:
# # 标注从yml读取配置
# config-type: yaml
# blends:
# # 自定义的标识也就是configId这里可以是任意值最好不要是中文
# tx1:
# #厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
# supplier: tencent
# #您的accessKey
# access-key-id: 您的accessKey
# #您的accessKeySecret
# access-key-secret: 您的accessKeySecret
# #您的短信签名
# signature: 您的短信签名
# #模板ID 非必须配置如果使用sendMessage的快速发送需此配置
# template-id: xxxxxxxx
# #您的sdkAppId
# sdk-app-id: 您的sdkAppId
# # 自定义的标识也就是configId这里可以是任意值最好不要是中文
# tx2:
# #厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
# supplier: tencent
# #您的accessKey
# access-key-id: 您的accessKey
# #您的accessKeySecret
# access-key-secret: 您的accessKeySecret
# #您的短信签名
# signature: 您的短信签名
# #模板ID 非必须配置如果使用sendMessage的快速发送需此配置
# template-id: xxxxxxxx
# #您的sdkAppId
# sdk-app-id: 您的sdkAppId
sms:
# 标注从yml读取配置0
# 自定义的标识也就是configId这里可以是任意值最好不要是中文
alibaba:
#厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: alibaba
#您的accessKey
access-key-id: LTAI5tDy2edL9LhW43rnus69
#您的accessKeySecret
access-key-secret: YWp44dcFrBICrjZgqvJBE7ZHArZfIP
#您的短信签名
signature: 阿里云短信测试
#模板ID 非必须配置如果使用sendMessage的快速发送需此配置
template-id: SMS_154950909
template-name: code
#您的sdkAppId
sdk-app-id: sms
requestUrl: dysmsapi.aliyuncs.com
# # 接口方法默认为 SendSms 如无特殊改变可以不用设置
# action: SendSms
# # 接口版本号默认为 2017-05-25 如无特殊改变可以不用设置
# version: 2017-05-25
# # 地域信息默认为 cn-hangzhou 如无特殊改变可以不用设置
# regionId: cn-hangzhou