一、验证码的作用
1、防止大量重复请求。一般在登录的时候需要验证码,验证码的作用就是拖延时间,让每次登录的操作时间间隔变长,这样可以防止有人暴力破解密码登录。
二、设计思路
1、最简单的验证码,就是一串数字了。小时候看到的就是这个样子的,4个数字。
2、这串数字应该是随机的。
3、这串数字是可以更换的(以前看到的换一张按钮)。
4、要有一个输入框,输入验证码。
5、每登录一次,若失败应该更换验证码。
6、稍微高级一点,验证码可以变成一张图片,防止恶意软件直接从前端代码获取验证码值。
7、更高级的验证码,可以改变验证的内容:比如验证中文,验证计算结果等;可以改变验证的方式,比如12306看名称选图,比如拖拽图片验证;可以改变验证码的获取方式,比如把验证码通过短信或电话发到用户的手机,通过邮件发到用户的邮箱等。(难度略大,在这里忽略掉这一条)
三、代码实现
1、最简单的验证码
①前端
1 <div class="yanzhengma"> 2 <span>验证码:</span> 3 <input type="text" name="yanzhengma" placeholder="请输入验证码"> 4 <span id="yanzhengmaInfo">1234</span> 5 <span onclick="changeYanzhengmaInfo();">换一张</span> 6 </div>
// 改变验证码的值 function changeYanzhengmaInfo() { var url = contextPath + '/changeYanzhengmaInfo.html?' + new Date().getTime(); $.post(url,function(data) { $("#yanzhengmaInfo").text(data); }); }
②后端
1 // 生成验证码 2 @Action("/changeYanzhengmaInfo") 3 public void changeYanzhengmaInfo() { 4 // 生成随机数,四位数,不足四位数(小于1000)的,给设一个值,大于9999的给设一个值 5 Random random = new Random(); 6 int r = random.nextInt(10000); 7 if (r < 1000) { 8 r = 2018; 9 } else if (r > 9999) { 10 r = 9999; 11 } 12 final String yanzhengma = random.nextInt(10000) + ""; 13 // 把值保存到session 14 final HttpSession session = ServletActionContext.getRequest().getSession(); 15 session.setAttribute("captcha", yanzhengma); 16 // 把值返回到前端 17 this.sendResponseMsg(yanzhengma); 18 } 19 20 /** 21 * 验证验证码. 22 * 23 * @throws UnsupportedEncodingException 24 * @author 25 */ 26 @Action("/checkCaptcha") 27 public void checkCaptcha() throws UnsupportedEncodingException { 28 this.request.setCharacterEncoding(ENCODE_UTF_8); 29 this.response.setContentType(CONTENT_TYPE); 30 final String yanzhengma = this.request.getParameter("yanzhengma"); 31 32 String captcha = this.session.get("captcha"); 33 if (captcha == null) { 34 sendFailMsg("", "验证码不存在,请刷新!"); 35 return; 36 } 37 if (captcha.equals(yanzhengma)) { 38 this.sendSuccessMsg(); 39 } else { 40 this.sendFailMsg(null, "验证码错误!"); 41 } 42 }
2、图片形式的验证码
①前端
与上边的不同,这里获取的验证码是一张图片,所以这里要从后台获取到的数据应该是验证码图片的链接。通过换链接的方式来达到换验证码的效果。
<li> <label class="u_label">验证码:</label> <input id="captcha" class="text-input captcha" name="captcha" type="text" placeholder="请输入验证码"> <a href="javascript:;" style="margin-left:20px;"><img id="captcha-img" width="80" height="36" src="${contextPath}/captchaImage.html" /></a> <span><a href="javascript:changeCaptchaImg();" style="height: 40px; line-height: 40px; margin-left: 10px;">换一张</a></span> </li> <span id="captchadwrong" style="margin-left:84px;color:red;display: none">请输入正确的验证码</span>
1 // 改获取图片的链接 2 function changeCaptchaImg() { 3 var imgUrl = contextPath + '/captchaImage.html?' + new Date().getTime(); 4 $('#captcha-img').attr('src', imgUrl); 5 } 6 7 // 验证验证码 8 function checkCaptcha() { 9 var captchaValue = $("input[name='captcha']").val(); 10 var captcha = false; 11 var captchadwrong = $('#captchadwrong'); 12 $.ajax({ 13 url: contextPath + '/checkCaptcha.html', 14 type: 'post', 15 dataType: 'json', 16 async: false, 17 data: { captcha: captchaValue }, 18 success: function(text) { 19 captcha = text.success; 20 } 21 }); 22 if (captcha == false) { //失败 23 captchadwrong.css('display', "inline-block"); 24 captchadwrong.text("请输入正确的验证码"); 25 return false; 26 } else { //成功 27 captchadwrong.css('display', "none"); 28 return true; 29 } 30 }
②后端
首先,需要引入一个jar包:simplecaptcha-1.2.1.jar
1 @Action("/captchaImage") 2 public void createCaptchaImage() { 3 // 自定义设置字体颜色和大小 最简单的效果 多种字体随机显示 4 final List<java.awt.Color> textColors = Arrays.asList(this.getRandColor(50, 200), this.getRandColor(50, 200)); 5 final List<Font> fontList = Lists.newArrayList(); 6 fontList.add(new Font("Viner Hand ITC", Font.TYPE1_FONT, 52));// 可以设置斜体之类的 7 fontList.add(new Font("Kristen ITC", Font.ITALIC, 45)); 8 fontList.add(new Font("Bradley Hand ITC", Font.HANGING_BASELINE, 52)); 9 fontList.add(new Font("Comic Sans ms", Font.PLAIN, 45)); 10 // 图片的背景(渐变,从 white 色到 white 色) 11 final GradiatedBackgroundProducer gbp = new GradiatedBackgroundProducer(Color.white, Color.white); 12 // 生成验证码对象:包括值Answer,时间Timestamp,图片Image,图片里包括颜色,宽高等信息 13 final Captcha captcha = new Captcha.Builder(CAPTCHA_WIDTH, CAPTCHA_HEIGHT).addNoise().addNoise() 14 // .gimp(new ShearGimpyRenderer 15 // (this.getRandColor(50, 200))) 16 .addText(new DefaultTextProducer(RANDOM_NUMBER, MY_CHARS), 17 new DefaultWordRenderer(textColors, fontList)) 18 .addBackground(gbp).build(); 19 // // 在session中存储生成的验证码 20 final HttpSession session = ServletActionContext.getRequest().getSession(); 21 OutputStream out = null; 22 try { 23 out = this.response.getOutputStream(); 24 this.response.reset(); 25 this.response.setContentType("image/jpeg"); 26 this.response.setHeader("Pragma", "No-cache"); 27 this.response.setHeader("Cache-Control", "no-cache"); 28 this.response.setDateHeader("Expires", 0); 29 ImageIO.write(captcha.getImage(), "JPG", out); 30 session.setAttribute(CAPTCHA, captcha); 31 out.flush(); 32 out.close(); 33 this.response.flushBuffer(); 34 } catch (final IOException e) { 35 CaptchaImageAction.LOGGER.error("发送验证码IO异常", e); 36 } finally { 37 if (out != null) { 38 try { 39 out.close(); 40 } catch (final IOException e) { 41 CaptchaImageAction.LOGGER.error("发送验证码IO异常", e); 42 } 43 } 44 } 45 } 46 47 48 /* 49 * 给定范围获得随机颜色 50 */ 51 private Color getRandColor(final int fc, final int bc) { 52 int tmpFc = fc; 53 int tmpBc = bc; 54 final Random random = new Random(); 55 if (tmpFc > MAX_RANDOM_NUMBER) { 56 tmpFc = MAX_RANDOM_NUMBER; 57 } 58 if (tmpBc > MAX_RANDOM_NUMBER) { 59 tmpBc = MAX_RANDOM_NUMBER; 60 } 61 final int r = tmpFc + random.nextInt(tmpBc - tmpFc); 62 final int g = tmpFc + random.nextInt(tmpBc - tmpFc); 63 final int b = tmpFc + random.nextInt(tmpBc - tmpFc); 64 return new Color(r, g, b); 65 } 66 67 68 /** 69 * 验证验证码. 70 * 71 * @throws UnsupportedEncodingException 72 * @author 73 */ 74 @Action("/checkCaptcha") 75 public void checkCaptcha() throws UnsupportedEncodingException { 76 this.request.setCharacterEncoding(ENCODE_UTF_8); 77 this.response.setContentType(CONTENT_TYPE); 78 final String captcha = this.request.getParameter(CaptchaImageAction.CAPTCHA); 79 80 Object object = this.session.get(CaptchaImageAction.CAPTCHA); 81 if (object == null) { 82 sendFailMsg("", "验证码不存在,请刷新!"); 83 return; 84 } 85 final Captcha captchaInSession = (Captcha) object; 86 final String answer = captchaInSession.getAnswer(); 87 // 忽略大小写比较 88 if (answer.equalsIgnoreCase(captcha)) { 89 this.sendSuccessMsg(); 90 } else { 91 this.sendFailMsg(null, "验证码错误!"); 92 } 93 }
③效果图