驗證碼想必大家都經常遇到,今天就給大家介紹一個比較簡單的圖片驗證碼的實現。
要實現驗證碼主要分生成和驗證兩步。首先生成,就是指某個用戶看到驗證碼後臺立馬生成的,然後把這個生成圖片的字符串保存放在session或者內存中;要驗證用戶輸入的字符串與生成的驗證碼是否一致,就是取出這個session中保存的字符串與用戶輸入的驗證碼進行比對即可。
一、html代碼
筆者寫了一個很簡單的html界面,來簡單模擬下過程,代碼如下:
<!DOCTYPE html>
<html>
<head>
<title>圖片驗證碼</title>
<meta charset="utf-8"/>
</head>
<body>
<input type="number" class="ui input row-1" placeholder="請輸入驗證碼" id="yzm">
<a href="javascript:void(0)" class="refresh_yzm"><img src="" id="randomImg"></a>
<button type="button" id="save_btn">提交</button>
<script src="/m/plugins/zepto/zepto.min.js" type="text/javascript"></script>
<script src="../../scripts/captcha/imageCode.js" type="text/javascript"></script>
</body>
</html>
頁面展示如下:
二、js代碼
交互邏輯代碼如下,比較簡單,所以也用不着做啥介紹:
/**
* 圖片驗證碼
*/
var mobileKey = '';
$(function() {
console.log('圖片驗證碼。。。');
getTicketImg();
//點擊驗證碼圖片
$('#randomImg').click(function() {
getTicketImg();
});
//提交
$('#save_btn').click(function() {
//獲取輸入框的驗證碼
var code = $('#yzm').val();
console.log('code:' + code + ', mobileKey:' + mobileKey);
var param = {
code: code,
mobileKey: mobileKey
};
$.post('/sys/captcha/validateImageCode.do', param, function(data) {
console.log('data:', data);
getTicketImg();
});
});
});
/**
* 獲取圖片驗證碼
*/
function getTicketImg() {
var ticket_key = Math.floor(Math.random() * 1000000);
mobileKey = ticket_key;
$("#yzm").val("");
var randomImg = "/sys/captcha/generateImageCode.do?mobileKey=" + ticket_key;
$("#randomImg").attr("src", randomImg);
}
三、後臺驗證碼圖片生成以及驗證
驗證碼圖片生成的代碼還是挺多的,這裏使用的是patchca這個插件,版本是0.5.0的,大家可以在網上去下載,上傳到自己私服的第三方庫。
代碼如下:
/**
* Project Name:qyk_testSpringMVC
* File Name:CaptchaController.java
* Package Name:com.qiyongkang.sys.controller
* Date:2017年2月7日上午9:49:30
* Copyright (c) 2017, Thinkive(http://www.thinkive.com/) All Rights Reserved.
*
*/
package com.qiyongkang.sys.controller;
import java.awt.Color;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.patchca.color.ColorFactory;
import org.patchca.filter.predefined.CurvesRippleFilterFactory;
import org.patchca.filter.predefined.DiffuseRippleFilterFactory;
import org.patchca.filter.predefined.DoubleRippleFilterFactory;
import org.patchca.filter.predefined.MarbleRippleFilterFactory;
import org.patchca.filter.predefined.WobbleRippleFilterFactory;
import org.patchca.service.ConfigurableCaptchaService;
import org.patchca.utils.encoder.EncoderHelper;
import org.patchca.word.RandomWordFactory;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.qiyongkang.sys.Constants;
import com.qiyongkang.sys.dto.ExtJsObject;
/**
* ClassName:CaptchaController <br/>
* Function: 驗證碼. <br/>
* Date: 2017年2月7日 上午9:49:30 <br/>
*
* @author qiyongkang
* @version
* @since JDK 1.6
* @see
*/
@Controller
@RequestMapping
public class CaptchaController {
/**
* 日誌類
*/
private static Logger logger = LogManager.getLogger(CaptchaController.class);
private static ConfigurableCaptchaService cs = new ConfigurableCaptchaService();
private static int MAX_LENGTH = 4;
private static int MIN_LENGTH = 4;
private static Random random = new Random();
private static Map<String, String> vcodeMap = new HashMap<String, String>();
public static void saveVcode(String key, String vcode) {
vcodeMap.put(key, vcode);
}
public static String getVcode(String key) {
return vcodeMap.get(key);
}
public static void removeVcode(String key) {
vcodeMap.remove(key);
}
public static void emptyAllVcode() {
vcodeMap.clear();
}
static {
cs.setColorFactory(new ColorFactory() // 隨機生成顏色
{
public Color getColor(int x) {
int[] c = new int[3];
int i = random.nextInt(c.length);
for (int fi = 0; fi < c.length; fi++) {
if (fi == i) {
c[fi] = random.nextInt(71);
} else {
c[fi] = random.nextInt(256);
}
}
return new Color(c[0], c[1], c[2]);
}
});
RandomWordFactory wf = new RandomWordFactory();
wf.setCharacters("123456789");// 設置驗證碼的內容
wf.setMaxLength(MAX_LENGTH);
wf.setMinLength(MIN_LENGTH);
cs.setWordFactory(wf);
}
/**
*
* generateImageCode: 生成圖片驗證碼. <br/>
*
* @author qiyongkang
* @param request
* @param response
* @since JDK 1.6
*/
@RequestMapping
public void generateImageCode(HttpServletRequest request, HttpServletResponse response) {
switch (random.nextInt(5)) {// 隨機生成不同形式驗證碼
case 0:
cs.setFilterFactory(new CurvesRippleFilterFactory(cs.getColorFactory()));// 取現波紋
break;
case 1:
cs.setFilterFactory(new MarbleRippleFilterFactory());// 大理石波紋
break;
case 2:
cs.setFilterFactory(new DoubleRippleFilterFactory());// 雙波紋
break;
case 3:
cs.setFilterFactory(new WobbleRippleFilterFactory());// 擺波紋
break;
case 4:
cs.setFilterFactory(new DiffuseRippleFilterFactory());// 雙波紋
break;
}
setResponseHeader(response); // 設置響應頭
HttpSession session = request.getSession(true);
OutputStream os = null;
String codeStr = "";
try {
os = response.getOutputStream();
codeStr = EncoderHelper.getChallangeAndWriteImage(cs, "png", os);
} catch (IOException e) {
logger.error("生成驗證碼圖片異常", e);
} finally {
if (os != null) {
try {
os.flush();
os.close();
} catch (IOException e) {
logger.error("關閉流異常", e);
}
}
}
logger.info("當前的SessionID=" + session.getId() + ", 驗證碼:" + codeStr);
String key = request.getParameter("mobileKey");
if (key == null) {
key = "";
}
//保存到map中
saveVcode(key, codeStr);
//放在session中
session.setAttribute(Constants.TICKET + key, codeStr);
}
/**
*
* validateImageCode: 校驗圖片驗證碼. <br/>
*
* @author qiyongkang
* @since JDK 1.6
*/
@RequestMapping
@ResponseBody
public ExtJsObject validateImageCode(HttpServletRequest request) {
ExtJsObject extJsObject = new ExtJsObject();
//code
String code = request.getParameter("code");
//mobileKey
String mobileKey = request.getParameter("mobileKey");
if (StringUtils.isEmpty(code) || StringUtils.isEmpty(mobileKey)) {
extJsObject.setSuccess(false);
extJsObject.setMsg("驗證碼不能爲空");
} else {
//判斷驗證碼是否正確, 兩重判斷,session中和map集合中的
HttpSession session = request.getSession();
if (code.equalsIgnoreCase(session.getAttribute(Constants.TICKET + mobileKey).toString())
&& code.equalsIgnoreCase(CaptchaController.getVcode(mobileKey))) {
CaptchaController.removeVcode(mobileKey);
extJsObject.setSuccess(true);
extJsObject.setMsg("驗證碼正確");
} else {
extJsObject.setSuccess(false);
extJsObject.setMsg("驗證碼錯誤");
}
}
return extJsObject;
}
/**
* 設置輸出流響應頭
*/
private void setResponseHeader(HttpServletResponse response) {
response.setContentType("image/png");
response.setHeader("cache", "no-cache");
response.setContentType("image/png");
response.setHeader("Cache-Control", "no-cache, no-store");
response.setHeader("Pragma", "no-cache");
long time = System.currentTimeMillis();
response.setDateHeader("Last-Modified", time);
response.setDateHeader("Date", time);
response.setDateHeader("Expires", time);
}
}
這裏因爲在前端會帶一個隨機碼參數過來,所以做了雙重驗證,更加安全;另外,大家還可以寫一個定時任務,每天清一次map中的所有key,防止佔用過多的內存;好了,就簡單介紹到這兒了,大家可以去試一試!