SpringBoot使用Captcha生成验证码
程序员文章站
2023-10-28 20:01:28
1. 基本结构使用captcha生成验证码, 利用redis存储验证码redis中的结构为, key是32位的uuid, value为captcha的4位随机字母以及数字的集合设定redis过期时间为...
1. 基本结构
使用captcha生成验证码, 利用redis存储验证码
redis中的结构为, key是32位的uuid, value为captcha的4位随机字母以及数字的集合
设定redis过期时间为1min, 即可实现过期验证码的自动失效
2. kaptcha的依赖
基本的依赖这里不再叙述, 主要说一下要导入captcha的依赖
<!--kaptcha--> <dependency> <groupid>com.github.penggle</groupid> <artifactid>kaptcha</artifactid> <version>2.3.2</version> </dependency>
所有的依赖如下
<?xml version="1.0" encoding="utf-8"?> <project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>2.4.0</version> <relativepath/> <!-- lookup parent from repository --> </parent> <groupid>com.wang</groupid> <artifactid>spring_security_framework</artifactid> <version>0.0.1-snapshot</version> <name>spring_security_framework</name> <description>demo project for spring boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!--redis--> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-data-redis</artifactid> </dependency> <!--jdbc--> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-jdbc</artifactid> </dependency> <!--springsecurity--> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-security</artifactid> </dependency> <!--thymeleaf--> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-thymeleaf</artifactid> </dependency> <!--validation--> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-validation</artifactid> </dependency> <!--springboot web--> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <!--mybatis--> <dependency> <groupid>org.mybatis.spring.boot</groupid> <artifactid>mybatis-spring-boot-starter</artifactid> <version>2.1.4</version> </dependency> <!--springsecurity with thymeleaf--> <dependency> <groupid>org.thymeleaf.extras</groupid> <artifactid>thymeleaf-extras-springsecurity5</artifactid> </dependency> <!--mysql connector--> <dependency> <groupid>mysql</groupid> <artifactid>mysql-connector-java</artifactid> <scope>runtime</scope> </dependency> <!--lombok--> <dependency> <groupid>org.projectlombok</groupid> <artifactid>lombok</artifactid> <optional>true</optional> </dependency> <!--test--> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-test</artifactid> <scope>test</scope> </dependency> <dependency> <groupid>org.springframework.security</groupid> <artifactid>spring-security-test</artifactid> <scope>test</scope> </dependency> <!--druid--> <dependency> <groupid>com.alibaba</groupid> <artifactid>druid-spring-boot-starter</artifactid> <version>1.2.2</version> </dependency> <!--fastjson--> <dependency> <groupid>com.alibaba</groupid> <artifactid>fastjson</artifactid> <version>1.2.74</version> </dependency> <!--log4j--> <dependency> <groupid>log4j</groupid> <artifactid>log4j</artifactid> <version>1.2.17</version> </dependency> <!--swagger2--> <dependency> <groupid>io.springfox</groupid> <artifactid>springfox-boot-starter</artifactid> <version>3.0.0</version> </dependency> <!--hutool--> <dependency> <groupid>cn.hutool</groupid> <artifactid>hutool-all</artifactid> <version>5.4.7</version> </dependency> <!--kaptcha--> <dependency> <groupid>com.github.penggle</groupid> <artifactid>kaptcha</artifactid> <version>2.3.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> </plugin> </plugins> </build> </project>
3. 配置springboot
配置springboot的配置文件, 这里主要关注一个session的过期时间
#port server: port: 80 servlet: session: timeout: 1 spring: application: name: springsecurityframework #database setting datasource: username: root password: 123456 url: jdbc:mysql://localhost:3306/security?useunicode=true&characterencoding=utf-8&servertimezone=asia/shanghai driver-class-name: com.mysql.cj.jdbc.driver type: com.alibaba.druid.pool.druiddatasource #druid setting druid: initial-size: 5 min-idle: 5 max-active: 20 max-wait: 60000 time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 30000 validation-query: select 1 from dual test-while-idle: true test-on-borrow: false test-on-return: false pool-prepared-statements: true #setting for druid statview and filter filters: stat,wall,log4j max-pool-prepared-statement-per-connection-size: 20 use-global-data-source-stat: true connection-properties: druid.stat.mergesql=true;druid.stat.slowsql #redis setting redis: host: 127.0.0.1 port: 6379 #thymeleaf thymeleaf: cache: false #mybatis mybatis: type-aliases-package: com.wang.entity mapper-locations: classpath:mybatis/mapper/*.xml configuration: map-underscore-to-camel-case: true
其余的配置, 如log4j, druid, springsecurity, redistemplate,这里就不再赘述
4. 配置captcha
我们可以通过java的配置类来配置captcha生成验证码的一些规则
package com.wang.spring_security_framework.config; import com.google.code.kaptcha.impl.defaultkaptcha; import com.google.code.kaptcha.util.config; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import java.util.properties; //kaptcha配置 @configuration public class kaptchaconfig { @bean public defaultkaptcha producer() { //properties类 properties properties = new properties(); // 图片边框 properties.setproperty("kaptcha.border", "yes"); // 边框颜色 properties.setproperty("kaptcha.border.color", "105,179,90"); // 字体颜色 properties.setproperty("kaptcha.textproducer.font.color", "blue"); // 图片宽 properties.setproperty("kaptcha.image.width", "110"); // 图片高 properties.setproperty("kaptcha.image.height", "40"); // 字体大小 properties.setproperty("kaptcha.textproducer.font.size", "30"); // session key properties.setproperty("kaptcha.session.key", "code"); // 验证码长度 properties.setproperty("kaptcha.textproducer.char.length", "4"); // 字体 properties.setproperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑"); //图片干扰 properties.setproperty("kaptcha.noise.impl","com.google.code.kaptcha.impl.defaultnoise"); //kaptcha 使用上述配置 config config = new config(properties); //defaultkaptcha对象使用上述配置, 并返回这个bean defaultkaptcha defaultkaptcha = new defaultkaptcha(); defaultkaptcha.setconfig(config); return defaultkaptcha; } }
5. 工具类
使用uuid作为key, 同时考虑到对验证码的输出结果可能有不同的要求, 这里写两个工具类来处理它们
uuidutil
package com.wang.spring_security_framework.util; import org.springframework.context.annotation.bean; import org.springframework.stereotype.component; import java.util.uuid; @component public class uuidutil { /** * 生成32位的随机uuid * @return 字符形式的小写uuid */ @bean public string getuuid32() { return uuid.randomuuid().tostring() .replace("-", "").tolowercase(); } }
captchautil
package com.wang.spring_security_framework.util; import com.google.code.kaptcha.impl.defaultkaptcha; import com.wang.spring_security_framework.service.captchaservice; import io.netty.handler.codec.base64.base64encoder; import org.springframework.beans.factory.annotation.autowired; import org.springframework.stereotype.component; import sun.misc.base64encoder; import javax.imageio.imageio; import java.awt.image.bufferedimage; import java.io.bytearrayoutputstream; import java.io.ioexception; import java.io.outputstream; import java.util.map; @component //captcha 生成工具 public class captchautil { @autowired private defaultkaptcha producer; @autowired private captchaservice captchaservice; //生成catchcreator的map public map<string, object> catchaimgcreator() throws ioexception { //生成文字验证码 string text = producer.createtext(); //生成文字对应的图片验证码 bufferedimage image = producer.createimage(text); //将图片写出 bytearrayoutputstream outputstream = new bytearrayoutputstream(); imageio.write(image, "jpg", outputstream); //对写出的字节数组进行base64编码 ==> 用于传递8比特字节码 base64encoder encoder = new base64encoder(); //生成token map<string, object> token = captchaservice.createtoken(text); token.put("img", encoder.encode(outputstream.tobytearray())); return token; } }
6. 接口以及实现类
1. 接口
package com.wang.spring_security_framework.service; import org.springframework.stereotype.service; import java.io.ioexception; import java.util.map; public interface captchaservice { //生成token map<string, object> createtoken(string captcha); //生成captcha验证码 map<string, object> captchacreator() throws ioexception; //验证输入的验证码是否正确 string versifycaptcha (string token, string inputcode); }
2. 实现类
package com.wang.spring_security_framework.service.serviceimpl; import com.google.code.kaptcha.impl.defaultkaptcha; import com.wang.spring_security_framework.service.captchaservice; import com.wang.spring_security_framework.util.captchautil; import com.wang.spring_security_framework.util.uuidutil; import org.springframework.beans.factory.annotation.autowired; import org.springframework.beans.factory.annotation.value; import org.springframework.data.redis.core.redistemplate; import org.springframework.data.redis.core.valueoperations; import org.springframework.stereotype.service; import java.io.ioexception; import java.util.hashmap; import java.util.map; import java.util.concurrent.timeunit; @service public class captchaserviceimpl implements captchaservice { @autowired private redistemplate<string, object> redistemplate; @autowired private uuidutil uuidutil; @autowired private captchautil captchautil; //从springboot的配置文件中取出过期时间 @value("${server.servlet.session.timeout}") private integer timeout; //uuid为key, 验证码为value放在redis中 @override public map<string, object> createtoken(string captcha) { //生成一个token string key = uuidutil.getuuid32(); //生成验证码对应的token 以token为key 验证码为value存在redis中 valueoperations<string, object> valueoperations = redistemplate.opsforvalue(); valueoperations.set(key, captcha); //设置验证码过期时间 redistemplate.expire(key, timeout, timeunit.minutes); map<string, object> map = new hashmap<>(); map.put("token", key); map.put("expire", timeout); return map; } //生成captcha验证码 @override public map<string, object> captchacreator() throws ioexception { return captchautil.catchaimgcreator(); } //验证输入的验证码是否正确 @override public string versifycaptcha(string token, string inputcode) { //根据前端传回的token在redis中找对应的value valueoperations<string, object> valueoperations = redistemplate.opsforvalue(); if (redistemplate.haskey(token)) { //验证通过, 删除对应的key if (valueoperations.get(token).equals(inputcode)) { redistemplate.delete(token); return "true"; } else { return "false"; } } else { return "false"; } } }
- 这里的验证, 只是简单的验证了输入是否能从redis中匹配, 返回了字符串
- 真实的验证中, 我们还要在逻辑中添加用户名和密码的考虑
7. controller
package com.wang.spring_security_framework.controller; import com.wang.spring_security_framework.service.captchaservice; import org.springframework.beans.factory.annotation.autowired; import org.springframework.web.bind.annotation.getmapping; import org.springframework.web.bind.annotation.requestparam; import org.springframework.web.bind.annotation.restcontroller; import java.io.ioexception; import java.util.map; @restcontroller public class logincontroller { @autowired captchaservice captchaservice; @getmapping("/captcha") public map<string, object> captcha() throws ioexception { return captchaservice.captchacreator(); } @getmapping("/login1") public string login(@requestparam("token") string token, @requestparam("inputcode") string inputcode) { return captchaservice.versifycaptcha(token, inputcode); } }
- captcha 用于获取一个验证码
- login1 用于接收到前端的请求后验证并返回结果
- login1 这里为了测试简便实用了get方法, 而实际中最好使用post方法, 这样安全性更高
8. 前端页面的实现
前端结构如图, 实现了一个简单的验证码
<!doctype html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"> <title>登录</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> </head> <body> <div> <div> <form th:action="@{/login1}" method="get"> <input type="text" id="username" placeholder="请输入用户名" name="username"> <br> <input type="password" id="password" placeholder="请输入密码" name="password"> <br> <input type="text" id="inputcode" placeholder="请输入验证码" maxlength="4" name="inputcode"> <!--通过隐藏域传递值, 在下面的验证码点击事件中, 将值绑定过来, 这样就可以获得最新的验证码对应的值了!--> <input id="token" value="" type="hidden" name="token"> <input type="submit" value="登录"> </form> </div> <div> <!-- 当用户链接时,void(0)计算为0,用户点击不会发生任何效果 --> <a href="javascript:void(0);" rel="external nofollow" title="点击更换验证码"> <!--this参数, 返回当前的dom元素--> <img src="" alt="更换验证码" id="imgverify" onclick="getverify(this)"> </a> </div> </div> <script> //获得img对象 let imgverify = $("#imgverify").get(0); //$(function())等同于$(document).ready(function()) ==> 页面加载完毕之后, 才执行函数 $(function () { getverify(imgverify); }); //onclick时间绑定的getverify函数 function getverify(obj) { $.ajax({ type: "get", url: "/captcha", success: function (result) { obj.src = "data:image/jpeg;base64," + result.img; $("#token").val(result.token); } }); } </script> </body> </html>
- 用一个 a 标签包围 img 标签, 这样如果图片没有加载出来也有一个超链接, 不过点了以后没有效果
- (function())等同于(function())等同于(document).ready(function()) ==> 页面加载完毕之后, 才执行函数, 这里必须要写这个函数, 否则第一次加载不会调用 onclick 方法, 也就不会生成验证码!
- 我们利用隐藏域将验证码的key传递到表单中, 我们在 img 的点击事件对应的函数的ajax回调函数中可以利用jquery操作dom, 顺带取出key值放到我们的隐藏域中, 这样提交的时候就会提交 key 和用户输入的 value 了
示例
验证通过
以上就是springboot使用captcha生成验证码的详细内容,更多关于springboot生成验证码的资料请关注其它相关文章!
上一篇: 带你摘草莓