Springboot +redis+⾕歌开源Kaptcha实现图片验证码功能
时间:2022-01-29 作者:look-word
Springboot +redis+⾕歌开源Kaptcha实现图片验证码功能
-
背景
- 注册-登录-修改密码⼀般需要发送验证码,但是容易被 攻击恶意调⽤
- 什么是短信-邮箱轰炸机
- 手机短信轰炸机是批、循环给⼿机⽆限发送各种⽹ 站的注册验 证码短信的⽅法。
- 公司带来的损失
- 短信⼀条5分钱,如果被⼤盗刷⼤家⾃⼰计算 邮箱通知不⽤钱,但被⼤盗刷,带宽、连接等都被占⽤,导致⽆法正常使⽤
- 如何避免⾃⼰的⽹站成为”⾁鸡“或者被刷呢
- 增加图形验证码(开发⼈员)
- 单IP请求次数限制(开发⼈员)
- 限制号码发送(⼀般短信提供商会做)
- 攻防永远是有的,只过加⼤了攻击者的成本,ROI划不 过来⾃然就放弃了
Kaptcha 框架介绍
-
⾕歌开源的⼀个可⾼度配置的实⽤验证 码⽣成⼯具
-
验证码的字体/⼤⼩/颜⾊
-
验证码内容的范围(数字,字⺟,中⽂汉字!)
-
验证码图⽚的⼤⼩,边框,边框粗细,边框颜⾊
-
验证码的⼲扰线 验证码的样式(⻥眼样式、3D、普通 模糊)
-
-
添加依赖
<!--kaptcha依赖包--> <dependency> <groupId>域名idou</groupId> <artifactId>kaptcha-spring-bootstarter</artifactId> <version>1.0.0</version> </dependency>
-
配置类
/** * 图像验证码的配置文件 * @author : look-word * @date : 2022-01-28 17:10 **/ @Configuration public class CaptchaConfig { /** * 验证码配置 * Kaptcha配置类名 * * @return */ @Bean @Qualifier("captchaProducer") public DefaultKaptcha kaptcha() { DefaultKaptcha kaptcha = new DefaultKaptcha(); Properties properties = new Properties(); //验证码个数 域名roperty(域名CHA_TEXTPRODUCER_CHAR_LENGTH, "4"); //字体间隔 域名roperty(域名CHA_TEXTPRODUCER_CHAR_SPACE,"8"); //⼲扰线颜⾊ //⼲扰实现类 域名roperty(域名CHA_NOISE_IMPL, "域名.域名ise"); //图⽚样式 域名roperty(域名CHA_OBSCURIFICATOR_IMPL, "域名.域名rRipple"); //⽂字来源 域名roperty(域名CHA_TEXTPRODUCER_CHAR_STRING, "0123456789"); Config config = new Config(properties); 域名onfig(config); return kaptcha; } }
实战
我的配置类
获取访问ip和生成MD5的工具类
public class CommonUtil {
/**
* 获取ip
* @param request
* @return
*/
public static String
getIpAddr(HttpServletRequest request) {
String ipAddress = null;
try {
ipAddress = 域名eader("xforwarded-for");
if (ipAddress == null ||
域名th() == 0 ||
"unknown".equalsIgnoreCase(ipAddress)) {
ipAddress =
域名eader("Proxy-Client-IP");
}
if (ipAddress == null ||
域名th() == 0 ||
"unknown".equalsIgnoreCase(ipAddress)) {
ipAddress =
域名eader("WL-Proxy-Client-IP");
}
if (ipAddress == null ||
域名th() == 0 ||
"unknown".equalsIgnoreCase(ipAddress)) {
ipAddress =
域名emoteAddr();
if
(域名ls("127.0.0.1")) {
// 根据⽹卡取本机配置的IP
InetAddress inet = null;
try {
inet =
域名ocalHost();
} catch (UnknownHostException e) {
域名tStackTrace();
}
ipAddress =
域名ostAddress();
}
}
// 对于通过多个代理的情况,第⼀个IP为客户端真实IP,多个IP按照\',\'分割
if (ipAddress != null &&
域名th() > 15) {
// "***.***.***.***".length()
// = 15
if (域名xOf(",") > 0)
{
ipAddress =
域名tring(0, 域名xOf(","));
}
}
} catch (Exception e) {
ipAddress="";
}
return ipAddress;
}
public static String MD5(String data) {
try {
域名ageDigest md =
域名nstance("MD5");
byte[] array =
域名st(域名ytes("UTF-8"));
StringBuilder sb = new
StringBuilder();
for (byte item : array) {
域名nd(域名xString((item & 0xFF) |
0x100).substring(1, 3));
}
return 域名ring().toUpperCase();
} catch (Exception exception) {
}
return null;
}
}
接口开发
@RestController
@RequestMapping("/api/v1/captcha")
public class CaptchaController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private Producer producer;
@RequestMapping("get_captcha")
public void getCaptcha(HttpServletRequest request, HttpServletResponse response){
String captchaText = 域名teText();
String key = getCaptchaKey(request);
// 十分钟过期
域名orValue().set(key,captchaText,10, 域名TES);
BufferedImage image = 域名teImage(captchaText);
ServletOutputStream outputStream=null;
try {
outputStream= 域名utputStream();
域名e(image,"jpg",outputStream);
域名h();
域名e();
} catch (IOException e) {
域名tStackTrace();
}
}
/**
* 生成redis验证码模块的key
* @param request
* @return
*/
private String getCaptchaKey(HttpServletRequest request){
String ipAddr = 域名pAddr(request);
// 请求头
String userAgent=域名eader("user-Agent");
String key="user_service:captcha:"+域名(ipAddr+userAgent);
return key;
}
}
配置文件
server:
port: 8080
spring:
redis:
host: redis锁在的ip
password: redis的密码
port: 端口号
lettuce:
pool:
# 连接池最⼤连接数(使⽤负值表示没有限制)
max-idle: 10
# 连接池中的最⼤空闲连接
max-active: 10
# 连接池中的最⼩空闲连接
min-idle: 0
# 连接池最⼤阻塞等待时间(使⽤负值表示没有限制)
max-wait: -1ms