1、使用场景
由于需要做一个前后端分离的项目,想着使用google验证码,由于年龄大了,这些知识啊,用完就忘,在这里记录一下。
登录时验证码设计:
- 使用google验证码工具,当前端在登录请求时,在后端生成验证码,同时也生成一个随机数(UUID)与该验证码对应。
- 使用redis作为缓存,将该随机数和验证码存储在redis中。
- 随机数的目的是将验证码与发起登录请求的用户联系起来。
- 当用户提交登录表单时,后端根据该随机数从redis中读取验证码与用户输入的验证码进行验证。
大概就是这样的一个设计思路,具体如下:
2、springboot使用google验证码
1、引入依赖
首先在pom文件中引入该验证码插件kaptcha
<!-- google 验证码 -->
<!-- https://mvnrepository.com/artifact/com.github.penggle/kaptcha -->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
2、编写配置类
引入依赖之后还需要编写配置类,在配置类里设置自己想要的验证码样式,包括颜色、大小、宽高等等。
我的配置类如下:
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;
@Configuration
public class KaptchaConfig {
@Bean
DefaultKaptcha producer() { //验证码的配置类
Properties properties = new Properties();
properties.put("kaptcha.border", "no"); //边框
properties.put("kaptcha.textproducer.font.color", "black"); //字体颜色
properties.put("kaptcha.textproducer.char.space", "5"); //字体间隔
properties.put("kaptcha.image.height", "40"); //图片高度
properties.put("kaptcha.image.width", "100"); //图片宽度
properties.put("kaptcha.textproducer.font.size", "30"); //字体大小
Config config = new Config(properties);
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
3、编写控制层
将下面的代码放到需要使用验证码的controller中
//获取登录验证码
@GetMapping("/captcha")
public Result Captcha() throws IOException {
String key = UUID.randomUUID().toString();
String code = producer.createText();
BufferedImage image = producer.createImage(code);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", outputStream);
BASE64Encoder encoder = new BASE64Encoder();
String str = "data:image/jpeg;base64,";
String base64Img = str + encoder.encode(outputStream.toByteArray());
redisUtils.hset(Constants.CAPTCHA_KEY, key, code, 120);
return Result.succ(
MapUtil.builder()
.put("userKey", key)
.put("captchaImg", base64Img)
.build()
);
}
上面用到了封装的redis工具类redisUtils中的hset方法,并设置了验证码过期时间120秒。
hset方法如下:
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
Result是编写的统一结果返回类,代码如下所示:
@Data
public class Result_ implements Serializable {
private int code;
private String msg;
private Object data;
public static Result_ succ(Object data) {
return succ(200, "操作成功", data);
}
public static Result_ fail(String msg) {
return fail(400, msg, null);
}
public static Result_ succ (int code, String msg, Object data) {
Result_ result = new Result_();
result.setCode(code);
result.setMsg(msg);
result.setData(data);
return result;
}
public static Result_ fail (int code, String msg, Object data) {
Result_ result = new Result_();
result.setCode(code);
result.setMsg(msg);
result.setData(data);
return result;
}
}
这里没有编写对于验证码的验证。
4、前端实现
验证码输入框代码如下:
<el-form-item label="验证码" prop="code" style="width: 380px">
<el-input placeholder="请输入验证码"v-model="loginForm.code"style="width: 172px; float: left" ></el-input>
<el-image class="captchaImg" :src="captchaImg" @click="getCaptcha()"></el-image>
</el-form-item>
验证码函数如下:
// 获取验证码
getCaptcha() {
this.$axios.get('/user/captcha1').then(res => {
this.loginForm.token = res.data.data.token
this.captchaImg = res.data.data.captchaImg
this.loginForm.code = ''
})
}