使用redis保存验证码

前情提要:

因为公司对软件进行安全扫描,发现安全漏洞。需要将现有app软件的登录、注册功能添加图形验证码功能。验证码数据的生成以及校验需要在后台进行。

可参考后台管理系统的登录功能(如下图)。但是研究代码发现该功能的校验是在前台进行的,并且数据是后台生成后直接保存在页面隐藏框中。点击“登录”时进行校验。

使用redis保存验证码_第1张图片

后台代码如下:

package com.cpic.caf.hsp.web.controller.verifyCode;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.dcits.common.util.VerifyCodeImg;
@RequestMapping("/ui/verifyCode")
@Controller
public class VerifyCode {
	/* 获取验证码图片 */
	protected final Logger logger = LoggerFactory.getLogger(this.getClass());

	@RequestMapping("/getVerifyCode")
	@ResponseBody
	public void getVerificationCode(HttpServletResponse response,
			HttpServletRequest request,HttpSession session) {

		try {

			int width = 180;

			int height = 45;

			BufferedImage verifyImg = new BufferedImage(width, height,
					BufferedImage.TYPE_INT_RGB);

			// 生成对应宽高的初始图片

			String randomText = VerifyCodeImg.drawRandomText(width, height,
					verifyImg);

			// 单独的一个类方法,出于代码复用考虑,进行了封装。

			// 功能是生成验证码字符并加上噪点,干扰线,返回值为验证码字符

			request.getSession().setAttribute("verifyCode", randomText);

			response.setContentType("image/png");// 必须设置响应内容类型为图片,否则前台不识别

			OutputStream os = response.getOutputStream(); // 获取文件输出流

			ImageIO.write(verifyImg, "png", os);// 输出图片流

			os.flush();

			os.close();// 关闭流

		} catch (IOException e) {

			this.logger.error(e.getMessage());

			logger.info("异常信息:",e);

		}

	}
	@RequestMapping("/checkVerifyCode")
	@ResponseBody
	public Map checkVerifyCode(HttpServletResponse response,
			HttpServletRequest request,HttpSession session,String code) {
		Map map = new HashMap();
		 String sessionCode = (String) request.getSession().getAttribute("verifyCode");
		 if (code != null && !"".equals(code) && sessionCode != null && !"".equals(sessionCode)) {
	            if (code.equalsIgnoreCase(sessionCode)) {
	            	map.put("message", "success");
	               return map;
	            } else {
	            	map.put("message", "fail");
	               return map;
	            }
	        } else {
	        	map.put("message", "fail");
	            return map;
	        }
	    }
}

前台代码如下:

js如下:


$(function(){
	var checkTrue = true;
	
	function login(){
		checkOut();
		if(checkTrue == true){
			var j_password = CryptoJS.SHA256($("#j_password").val()+$("#j_username").val());
			$.ajax({
				type:"POST",
				dataType:"text",
				url:"./j_spring_security_check",
				data:"j_password="+j_password+"&j_username="+$('#j_username').val(),
				success:function(data){
					 var da = $.parseJSON(data);
					 if(da.authentication== "true"){
						 sessionStorage.token = da.token;
						 window.top.location.href="./home";//home
					 }else{
						 $("#err").empty();
						 $("#_password").val("");
						 $("#err").append("用户名或密码错误!");
					 }
					 
				 },
				error:function(data){
					alert("失败");
				 }
			});
		}
	}
	
	$("#j_login").click(function(){
		var code = $("input[name='verifyInput']").val();
	    var inputCode = document.getElementById("inputCode").value;
	    var callerKeyId = sessionStorage.callerKeyId;
	    var sessionId = sessionStorage.sessionId;
	    var applicationId = sessionStorage.applicationId;
	    if(!!callerKeyId && !!sessionId  && !!applicationId ){
	    	var j_password = CryptoJS.SHA256($("#j_password").val()+$("#j_username").val());
			$.ajax({
				type:"POST",
				dataType:"text",
				url:"./j_spring_security_check",
				data:"j_password="+j_password+"&j_username="+$('#j_username').val()+"&verifyCode="+inputCode,
				success:function(data){
					 var da = $.parseJSON(data);
					 if(da.authentication== "true"){
						 sessionStorage.token = da.token;
						 window.top.location.href="./home";//home
					 }else{
						alert('登录失败,请联系管理员添加此用户');
						closeWindow();
					 }
				 },
				error:function(data){
					alert('打开系统失败,系统错误');
					closeWindow();
				 }
			});
	    }else{
	    	$("#err").empty();
	    	if (inputCode.length <= 0) { 
//		    	layer.alert('请输入验证码!', {closeBtn: 0});
	    		$("#err").append("请输入验证码!");
		    }else {
				if(checkTrue == true){
					var j_password = CryptoJS.SHA256($("#j_password").val()+$("#j_username").val());
					$.ajax({
						type:"POST",
						dataType:"text",
						url:"./j_spring_security_check",
						data:"j_password="+j_password+"&j_username="+$('#j_username').val()+"&verifyCode="+inputCode,
						success:function(data){
							 var da = $.parseJSON(data);
							 if(da.authentication== "true"){
								 sessionStorage.token = da.token;
								 window.top.location.href="./home";//home
							 }else{
								 $("#err").empty();
								 changeCode();
								 $("#inputCode").val('');
								 if(da.authentication== "validCodeFalse"){
									 $("#err").append("验证码错误!");
								 }else if(da.authentication== "loginInfoFalse"){
									 $("#_password").val("");
									 $("#err").append("用户名或密码错误!");
								 }
							 }
						 },
						error:function(data){
							alert("失败");
						 }
					});
				}
		    }  
	    }
	});
	
	$("body").keydown(function(event) {
	    if (event.keyCode == "13" || event.which == 13) {//keyCode=13是回车键
	    	$("#j_login").click();
	    }
	});  
	
	function checkOut() {
		if($("#j_password").val()==""||$("#j_username").val()==""){
			$("#err").empty();
			$("#err").append("用户名或密码为空!");
			checkTrue = false;
		}else{
			checkTrue = true;
		}
	}
	
	$("#resetButton").click(function(){
		$("#j_username").val("");
		$("#j_password").val("");
		$("#inputCode").val("");
		$("#err").empty();
	});
});

因此,这个后台管理系统的登录功能不太适用于app的登录、注册需求。

思考:

1、如果使用redis保存验证码数据,那么key值存什么?

我自己想到的是保存客户端的用户ip作为key值。

2、如果使用redis保存验证码数据,那么如何删除已经使用过或者已经过期的数据?

redis自带删除功能,定时删除、惰性删除、定期删除。

3、redis的使用,以及如何验证数据。

redis有客户端。

redis的数据是保存在内存中。(其实并没有很理解是哪里。)

改良之后的代码:

package com.cpic.caf.hsp.app.controller.verifyCode;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.jfree.util.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.cpic.caf.hsp.utils.redis.RedisUtil;
import com.dcits.common.util.VerifyCodeImg;

@RequestMapping("/ui/verifyCode")
@Controller
public class VerifyCode {
	/* 获取验证码图片 */
	protected final Logger logger = LoggerFactory.getLogger(this.getClass());
	@Autowired
	private RedisUtil redisUtil;
	
	@RequestMapping("/getVerifyCode")
	@ResponseBody
	public void getVerificationCode(HttpServletResponse response,
			HttpServletRequest request,HttpSession session) {
		try {
			int width = 180;
			int height = 45;
			BufferedImage verifyImg = new BufferedImage(width, height,
					BufferedImage.TYPE_INT_RGB);
			// 生成对应宽高的初始图片
			String randomText = VerifyCodeImg.drawRandomText(width, height,
					verifyImg);
			// 单独的一个类方法,出于代码复用考虑,进行了封装。
			// 功能是生成验证码字符并加上噪点,干扰线,返回值为验证码字符
			//request.getSession().setAttribute("verifyCode", randomText);
			String ip = request.getRemoteAddr();
			redisUtil.setOp(ip+"_VerifyCode", randomText);
			Log.info("ip_VerifyCode-----"+ip+"_"+randomText);
			redisUtil.setEx(ip+"_VerifyCode", 60, randomText);
				
			response.setContentType("image/png");// 必须设置响应内容类型为图片,否则前台不识别
			OutputStream os = response.getOutputStream(); // 获取文件输出流
			ImageIO.write(verifyImg, "png", os);// 输出图片流
			os.flush();
			os.close();// 关闭流
		} catch (IOException e) {
			this.logger.error(e.getMessage());
			logger.info("异常信息:",e);
		}
	}
	
	@RequestMapping("/checkVerifyCode")
	@ResponseBody
	public Map checkVerifyCode(HttpServletResponse response,
			HttpServletRequest request,HttpSession session,String code) {
		Map map = new HashMap();
		 //String sessionCode = (String) request.getSession().getAttribute("verifyCode");
		//从redis中获取
		String ip = request.getRemoteAddr();
		String redisCode = redisUtil.getOp(ip+"_VerifyCode");
		if (code != null && !"".equals(code) && redisCode != null && !"".equals(redisCode)) {
	        if (code.equalsIgnoreCase(redisCode)) {
	            map.put("message", "success");
	            return map;
	        } else {
	            map.put("message", "fail");
	            return map;
	        }
	    } else {
	        map.put("message", "fail");
	        return map;
	    }
	}
	
	
}

 

 

 

你可能感兴趣的:(使用redis保存验证码)