刚开始使redis,踩了不少坑,redis的key不好确定,前端用于刷新验证码不好找到一个确定的值,后面我是从后端给前端传送一个精确到毫秒的时间,前端在刷新验证码的时候,将这个时间传过来作为key使用,同时在登录的时候也传送这个时间戳过来,作为redis value的验证。
1、刷新验证码的时间
/**
* 获取系统当前毫秒数
* @since 2019-12-02
* @return
*/
@RequestMapping(value = "/redisVerifyCodeTime", method = RequestMethod.POST)
@ResponseBody
public BaseResponse redisVerifyCodeTime(HttpServletRequest request) {
BaseResponse response = BaseResponse.success();
try {
Long oldtimestamp=System.currentTimeMillis();
response.setExtData(ImmutableMap.builder().put("oldtimestamp", oldtimestamp).build());
}catch (Exception e) {
logger.error("redisVerifyCodeTime error", e);
return BaseResponse.fail();
}
return response;
}
2、生成验证码并保存到redis中,给前端传递的是一个图片
@RequestMapping("/redisVerifyCode")
public void verifyCode (HttpServletRequest request, HttpServletResponse response) {
String oldtimestamp = request.getParameter("oldtimestamp");
BufferedImage image = new BufferedImage(WIDTH, HIGHT,
BufferedImage.TYPE_INT_RGB);
// step2,获得画笔
Graphics2D g = image.createGraphics();
// step3,¸给画布填充一个随机的颜色
SecureRandom r = new SecureRandom();
try{
r = SecureRandom.getInstance("SHA1PRNG");
}catch(NoSuchAlgorithmException e){
e.printStackTrace();
}
g.fillRect(0, 0, WIDTH, HIGHT);
// step4, 在画布上绘画
g.setColor(new Color(0, 0, 0));
String str = "0123456789abcdefhijkmnpqrstuvwxyz0123456789ABCDEFGHJKLMNPQRSTUVWXYZ0123456789";
String code = "";
for (int i = 0; i < 4; i++) {
g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
int h = (int) (20 + 10 * r.nextDouble());
g.setFont(new Font(null, h, h));
String ch = String.valueOf(str.charAt(r.nextInt(str.length())));
//增加验证码识别难度
AffineTransform trans = new AffineTransform();
double radians = Math.toRadians(Math.random() * 25.0D + 10.0D);
int anchorx = 17 * i + 8;
trans.rotate(radians, anchorx, 20.0D);
float scaleSize = r.nextFloat() + 0.8F;
if (scaleSize > 1.0F) {
scaleSize = 1.0F;
}
trans.scale(scaleSize, scaleSize);
g.setTransform(trans);
g.drawString(ch, i * WIDTH / 5, h);
code = code + ch;
}
//将验证码保存到redis中
redisManager.put(VERIFYCODE_PREX + oldtimestamp, code, 10, TimeUnit.MINUTES);
// 禁止图像缓存。
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
try {
OutputStream ops = response.getOutputStream();
javax.imageio.ImageIO.write(image, "jpeg", ops);
}catch (Exception e){
e.printStackTrace();
}
}
3、前端获取验证码
changeVerifyImg(){
apiVerifyCodeTime({}).then(res => {
if (res.resultCode == 1000) {//
this.oldtimestamp = res.extData.oldtimestamp;
} else {
this.oldtimestamp = new Date().getTime();
}
this.verifyUrl = this.baseURL+'/globalmall/approvalForApp/redisVerifyCode?'+this.timeSign();
}, err => {
});
},
timeSign(){
let obj = {oldtimestamp:this.oldtimestamp};
obj = encryption(obj);
return obj;
}
4、前端登录实现
onSubmit() {
// Disabled submit button
this.beforeSubmit();
console.log(sm4.encode({input:this.password,key:this.publicKey}));
// Login...
this.$store.dispatch('login',{
userName: sm4.encode({input:this.userName,key:this.publicKey}),
password: sm4.encode({input:this.password,key:this.publicKey}),
verifyCode: sm4.encode({input:this.verifyCode,key:this.publicKey}),
oldtimestamp: this.oldtimestamp
}).then(res => {
// Success handle
if (res.resultCode == 1000) this.onSuccess(res);//登陆成功
else {//提示框
this.showConfirm = true;
this.message = res.showMsg;
this.changeVerifyImg();
}
}, err => {
// Error handle
this.onError(err);
this.changeVerifyImg();
})
},
5、后端登录验证
String oldtimestamp = request.getParameter("oldtimestamp");
String userName = new SM4Utils().decode(request.getParameter("userName"), SM4_KEY);
String password = new SM4Utils().decode(request.getParameter("password"), SM4_KEY);
String verifyCode = new SM4Utils().decode(request.getParameter("verifyCode"), SM4_KEY);
if(null == verifyCode || "".equals(verifyCode)){
return BaseResponse.fail("验证码为空,请重新输入");
}else if(!redisManager.exists(VERIFYCODE_PREX + oldtimestamp)){
return BaseResponse.fail("验证码过期");
}else if(!verifyCode.equalsIgnoreCase(redisManager.get(VERIFYCODE_PREX + oldtimestamp))){
return BaseResponse.fail("验证码错误");
}