時間:2017年07月09日星期日
說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com
教學源碼:無
學習源碼:https://github.com/zccodere/s...
主要內(nèi)容
驗證碼歷史 課程內(nèi)容 不同方案對比 設計與實現(xiàn) 總結1-2 驗證碼歷史
驗證碼歷史
無驗證碼:垃圾騷擾 Luis von Ahn:Captcha 不斷的升級 去驗證碼
常見驗證碼
1-3 項目介紹完成類似最后一張圖片的驗證碼設計與實現(xiàn)
對比方案 完成設計 編碼實現(xiàn) 結果演示
結果演示
不同方案對比(一)
瀏覽器請求驗證碼圖片 服務器返回驗證碼圖片及圖片標識 瀏覽器提交驗證碼 服務器驗證圖片內(nèi)容及標識
不同方案對比(二)
瀏覽器請求驗證碼圖片 服務器返回驗證碼圖片及圖片標識 瀏覽器提交驗證碼 圖片文字/計算結果等 坐標 服務器驗證 驗證圖片內(nèi)容及標識 驗證坐標及標識
設計與實現(xiàn)
包結構 --controller、generator 主要類及作用 --Image:生成驗證碼圖片核心類 --BufferedImageWrap:圖片包裝類 --ImageGroup:原始圖片分組 --GenerateImageGroup:單次驗證使用圖片組 --Cache:單次驗證數(shù)據(jù)緩存 --LoginController
程序設計:技術選擇
教學使用
SpringMVC JSP Spring(4.0.5)
學習使用
SpringBoot Freemarker
思路整理
每次顯示幾張圖片:由8張小圖組成的一張大圖 答案圖片位置 選中位置坐標 坐標驗證 前后關聯(lián)第二章:圖片生成及頁面顯示 2-1 頁面結構及LoginController介紹
部分代碼演示:源碼請到我的github地址查看
login.html
登錄
LoginController類
package com.myimooc.identifying.controller; import java.io.IOException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import com.myimooc.identifying.generator.Image; import com.myimooc.identifying.generator.ImageResult; /** * 登錄控制器 * @author ZhangCheng on 2017-07-09 * */ @Controller public class LoginController { /** * 登錄主頁 * @param model * @param request * @param response * @return */ @RequestMapping("/login") public String identify(Model model,HttpServletRequest request,HttpServletResponse response){ try{ ImageResult imageResult = Image.generateImage(); model.addAttribute("file", imageResult.getName()); model.addAttribute("tip", imageResult.getTip()); System.out.println(imageResult.getName() + imageResult.getTip()); Cookie cookie = new Cookie("note",imageResult.getUniqueKey()); response.addCookie(cookie); request.getSession().setAttribute(imageResult.getUniqueKey(), imageResult); }catch(Exception e){ System.out.println("獲取圖片失敗"); e.printStackTrace(); } return "login"; } /** * 刷新圖片 * * @param request * @return * @throws IOException */ @RequestMapping(value = "/getPng") @ResponseBody public String getPng(HttpServletRequest request) throws IOException{ ImageResult imageResult = Image.generateImage(); ((HttpServletRequest) request).getSession().setAttribute("imageResult", imageResult); return imageResult.getName() + "," + imageResult.getTip(); } /** * 驗證消息 * * @param location * @param request * @param userName * @param password * @return */ @PostMapping("/dologin") @ResponseBody public String doLogin(String location, HttpServletRequest request, String userName, String password, RedirectAttributes redirectAttributes) { System.out.println("驗證坐標:"+ location); Cookie[] cookies = ((HttpServletRequest) request).getCookies(); Cookie note = null; for (Cookie cookie : cookies) { if (cookie.getName().equals("note")) { note = cookie; break; } } if(null == note){ return "ERROR"; } ImageResult imageResult = (ImageResult)request.getSession().getAttribute(note.getValue()); if(validate(location,imageResult)){ return "OK"; } return "ERROR"; } /** * 驗證是否正確 * @param locationString * @param imageResult * @return */ private boolean validate(String locationString, ImageResult imageResult) { String[] resultArray = locationString.split(";"); int[][] array = new int[resultArray.length][2]; for (int i = 0; i2-2 如何生成圖片generateImage=0 && y<75){ return xLocation(x); }else if(y >=75 && y<=150){ return xLocation(x)+4; }else{ // 臟數(shù)據(jù) return -1; } } private int xLocation(int x) { if(x >=0 && x<75){ return 0; }else if(x >=75 && x<150){ return 1; }else if(x >=150 && x<225){ return 2; }else if(x >=225 && x<=300){ return 3; }else{ // 臟數(shù)據(jù) return -1; } } }
Image類
package com.myimooc.identifying.generator; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.UUID; import javax.imageio.ImageIO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 生成驗證碼圖片核心類 * @author ZhangCheng on 2017-07-09 * */ public class Image { private static final Logger log= LoggerFactory.getLogger(Image.class); private static Map2-3 如何將圖片融合mergeImageimageGroupMap=new HashMap<>(); private static Map > countGroupMap=new HashMap<>(); /** * 功能:由小圖生成一種大圖 * @return * @throws IOException */ public static ImageResult generateImage()throws IOException{ // 初始化 initImageGroup(); log.debug("初始化完成"); GenerateImageGroup generateImageGroup = randomImageGroups(); List images = new ArrayList (); // 找到圖片干擾項 for (ImageGroup group : generateImageGroup.getGroups()) { for (String imgName : group.getImages()) { images.add(new BufferedImageWrap(false,getBufferedImage(imgName))); } } // 找到圖片答案項 for(String imgName : generateImageGroup.getKeyGroup().getImages()){ images.add(new BufferedImageWrap(true,getBufferedImage(imgName))); } return mergeImage(images,generateImageGroup.getKeyGroup().getName()); } /** * 功能:根據(jù)圖片名稱獲得圖片緩沖流 * @param imgName * @return * @throws IOException */ private static BufferedImage getBufferedImage(String imgName)throws IOException { String rootPath = Image.class.getClassLoader().getResource("sourceImage/").getPath(); String imgPath = rootPath + imgName; File file = new File(imgPath); return ImageIO.read(file); } /** * 功能:將小圖合并成一種大圖 * @param images * @param name * @return */ private static ImageResult mergeImage(List imageWraps, String tip) { Collections.shuffle(imageWraps); // 原始圖片寬200像素,高200像素 int width = 200; int high = 200; int totalWidth = width * 4; BufferedImage destImage = new BufferedImage(totalWidth,400,BufferedImage.TYPE_INT_RGB); int x1 = 0; int x2 = 0; int order = 0; List keysOrderList = new ArrayList (); StringBuilder keysOrder = new StringBuilder(); Set keySet = new HashSet (); for(BufferedImageWrap image : imageWraps){ int[] rgb = image.getBufferedImage().getRGB(0, 0, width, high, null, 0, width); if(image.isKey()){ keysOrderList.add(order); int x = (order % 4) * 200; int y = order < 4 ? 0:200; keySet.add(order); keysOrder.append(order).append("(").append(x).append(",").append(y).append(")|"); } if(order < 4 ){ // 設置上半部分的RGB destImage.setRGB(x1, 0, width,high,rgb,0,width); x1 += width; }else{ destImage.setRGB(x2, high, width,high,rgb,0,width); x2 += width; } order++; } keysOrder.deleteCharAt(keysOrder.length() - 1); System.out.println("答案位置:" + keysOrder); String fileName = UUID.randomUUID().toString().replaceAll("-", "") + ".jpeg"; String rootPath = Image.class.getClassLoader().getResource("static/targetImage/").getPath(); //String rootPath = Image.class.getClassLoader().getResource("sourceImage/").getPath(); log.info("根路徑:{}",rootPath); String fileUrl = rootPath + fileName; // 保存圖片 saveImage(destImage,fileUrl,"png"); ImageResult ir = new ImageResult(); ir.setName(fileName); ir.setKeySet(keySet); ir.setUniqueKey(fileName); ir.setTip(tip); return ir; } /** * 功能:將圖片寫入指定的路徑 * @param destImage * @param fileUrl * @param string */ private static void saveImage(BufferedImage destImage, String fileUrl, String format) { File file=new File(fileUrl); log.debug(file.getAbsolutePath()); try { ImageIO.write(destImage,format,file); } catch (IOException e) { log.info("圖片寫入失敗"); e.printStackTrace(); } } /** * 功能:隨機生成圖片答案和干擾組 * @return */ private static GenerateImageGroup randomImageGroups(){ List result = new ArrayList (); int num = random(0, imageGroupMap.size() - 1); String name = new ArrayList (imageGroupMap.keySet()).get(num); ImageGroup keyGroup = imageGroupMap.get(name); Map > thisCountGroupMap = new HashMap<>(countGroupMap); thisCountGroupMap.get(keyGroup.getCount()).remove(name); // 假設總量8個,每種名稱圖片只有2個或4個,為了邏輯簡單些 int leftCount = 8 - keyGroup.getCount(); if(leftCount == 4){ if(new Random().nextInt() % 2 == 0){ List groups = new ArrayList (thisCountGroupMap.get(4).values()); if(groups.size() > 1){ num = random(0, groups.size() - 1); }else{ num = 0; } result.add(groups.get(num)); }else{ List groups = new ArrayList (thisCountGroupMap.get(2).values()); int num1 = random(0, groups.size() - 1); result.add(groups.get(num1)); int num2 = random(0, groups.size() - 1,num1); result.add(groups.get(num2)); } }else if(leftCount == 6){ if(new Random().nextInt() % 2 == 0){ List groups1 = new ArrayList (thisCountGroupMap.get(4).values()); int num1 = random(0, groups1.size() - 1); result.add(groups1.get(num1)); List groups2 = new ArrayList (thisCountGroupMap.get(2).values()); int num2 = random(0, groups2.size() - 1); result.add(groups2.get(num2)); }else{ List groups = new ArrayList (thisCountGroupMap.get(2).values()); int num1 = random(0, groups.size() - 1); result.add(groups.get(num1)); int num2 = random(0, groups.size() - 1,num1); result.add(groups.get(num2)); int num3 = random(0, groups.size() - 1,num1,num2); result.add(groups.get(num3)); } } return new GenerateImageGroup(keyGroup, result); } /** * 功能:初始化圖片組。后期優(yōu)化可從數(shù)據(jù)庫獲取 */ private static void initImageGroup(){ ImageGroup group1 = new ImageGroup("包包",4,"bao/1.jpg","bao/2.jpg","bao/3.jpg","bao/4.jpg"); ImageGroup group2 = new ImageGroup("老虎",4,"laohu/1.jpg","laohu/2.jpg","laohu/3.jpg","laohu/4.jpg"); ImageGroup group3 = new ImageGroup("糖葫蘆",4,"tanghulu/1.jpg","tanghulu/2.jpg","tanghulu/3.jpg","tanghulu/4.jpg"); ImageGroup group4 = new ImageGroup("小慕",4,"xiaomu/1.jpg","xiaomu/2.jpg","xiaomu/3.jpg","xiaomu/4.jpg"); ImageGroup group5 = new ImageGroup("柚子",4,"youzi/1.jpg","youzi/2.jpg","youzi/3.jpg","youzi/4.jpg"); ImageGroup group6 = new ImageGroup("訂書機",2,"dingshuji/1.jpg","dingshuji/2.jpg"); ImageGroup group7 = new ImageGroup("蘑菇",2,"mogu/1.jpg","mogu/2.jpg"); ImageGroup group8 = new ImageGroup("磁鐵",2,"citie/1.jpg","citie/2.jpg"); ImageGroup group9 = new ImageGroup("土豆",4,"tudou/1.jpg","tudou/2.jpg","tudou/3.jpg","tudou/4.jpg"); ImageGroup group10 = new ImageGroup("兔子",4,"tuzi/1.jpg","tuzi/2.jpg","tuzi/3.jpg","tuzi/4.jpg"); ImageGroup group11 = new ImageGroup("仙人球",4,"xianrenqiu/1.jpg","xianrenqiu/2.jpg","xianrenqiu/3.jpg","xianrenqiu/4.jpg"); initMap(group1,group2,group3,group4,group5,group6,group7,group8,group9,group10,group11); } /** * 功能:初始化所有圖片組 * @param groups */ private static void initMap(ImageGroup... groups) { for (ImageGroup group : groups) { imageGroupMap.put(group.getName(),group); if(!countGroupMap.containsKey(group.getCount())){ countGroupMap.put(group.getCount(),new HashMap ()); } countGroupMap.get(group.getCount()).put(group.getName(),group); } } /** * 功能:生成隨機整數(shù) * @param min * @param max * @return */ private static int random(int min,int max){ Random random = new Random(); return random.nextInt(max - min + 1) + min; } /** * 功能:生成隨機整數(shù)不在指定整數(shù)數(shù)組里 * @param min * @param max * @param not * @return */ private static int random(int min,int max,Integer... not){ int num = random(min,max); List notList = Arrays.asList(not); while(notList.contains(num)){ num = random(min,max); } return num; } }
/** * 功能:將小圖合并成一種大圖 * @param images * @param name * @return */ private static ImageResult mergeImage(List第三章:驗證過程及總結 3-1 驗證驗證碼過程及總結imageWraps, String tip) { Collections.shuffle(imageWraps); // 原始圖片寬200像素,高200像素 int width = 200; int high = 200; int totalWidth = width * 4; BufferedImage destImage = new BufferedImage(totalWidth,400,BufferedImage.TYPE_INT_RGB); int x1 = 0; int x2 = 0; int order = 0; List keysOrderList = new ArrayList (); StringBuilder keysOrder = new StringBuilder(); Set keySet = new HashSet (); for(BufferedImageWrap image : imageWraps){ int[] rgb = image.getBufferedImage().getRGB(0, 0, width, high, null, 0, width); if(image.isKey()){ keysOrderList.add(order); int x = (order % 4) * 200; int y = order < 4 ? 0:200; keySet.add(order); keysOrder.append(order).append("(").append(x).append(",").append(y).append(")|"); } if(order < 4 ){ // 設置上半部分的RGB destImage.setRGB(x1, 0, width,high,rgb,0,width); x1 += width; }else{ destImage.setRGB(x2, high, width,high,rgb,0,width); x2 += width; } order++; } keysOrder.deleteCharAt(keysOrder.length() - 1); System.out.println("答案位置:" + keysOrder); String fileName = UUID.randomUUID().toString().replaceAll("-", "") + ".jpeg"; String rootPath = Image.class.getClassLoader().getResource("static/targetImage/").getPath(); //String rootPath = Image.class.getClassLoader().getResource("sourceImage/").getPath(); log.info("根路徑:{}",rootPath); String fileUrl = rootPath + fileName; // 保存圖片 saveImage(destImage,fileUrl,"png"); ImageResult ir = new ImageResult(); ir.setName(fileName); ir.setKeySet(keySet); ir.setUniqueKey(fileName); ir.setTip(tip); return ir; } /** * 功能:將圖片寫入指定的路徑 * @param destImage * @param fileUrl * @param string */ private static void saveImage(BufferedImage destImage, String fileUrl, String format) { File file=new File(fileUrl); log.debug(file.getAbsolutePath()); try { ImageIO.write(destImage,format,file); } catch (IOException e) { log.info("圖片寫入失敗"); e.printStackTrace(); } }
總結
驗證碼歷史 不同方案對比 設計與實現(xiàn) 總結
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67325.html
摘要:時間年月日星期五說明本文部分內(nèi)容均來自慕課網(wǎng)。線性堆疊式二維碼示意圖矩陣式二維碼在一個矩形空間通過黑白像素在矩陣中的不同分布進行編碼。 時間:2017年06月23日星期五說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學示例源碼:無個人學習源碼:https://github.com/zccodere/s... 第一章:二維碼的概念 1-1 二維碼概述...
摘要:時間年月日星期一說明本文部分內(nèi)容均來自慕課網(wǎng)。多用于網(wǎng)絡加密。散列函數(shù)函數(shù)或消息摘要函數(shù)主要作用散列函數(shù)用來驗證數(shù)據(jù)的完整性。 時間:2017年4月10日星期一說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學示例源碼:https://github.com/zccodere/s...個人學習源碼:https://github.com/zccodere...
摘要:慕課網(wǎng)發(fā)送郵件學習總結時間年月日星期六說明本文部分內(nèi)容均來自慕課網(wǎng)。 慕課網(wǎng)《Spring Boot 發(fā)送郵件》學習總結 時間:2018年09月08日星期六 說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):https://www.imooc.com 教學源碼:https://github.com/ityouknow/... 學習源碼:https://github.com/zccoder...
摘要:時間年月日星期五說明本文部分內(nèi)容均來自慕課網(wǎng)。本套課程介紹微信公眾號開發(fā),主要涉及公眾號介紹編輯模式介紹開發(fā)模式介紹等。慕課網(wǎng)是垂直的互聯(lián)網(wǎng)技能免費學習網(wǎng)站。 時間:2017年08月11日星期五說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學源碼:https://github.com/zccodere/s...學習源碼:https://github...
摘要:時間年月日星期三說明本文部分內(nèi)容均來自慕課網(wǎng)。用戶過生日,系統(tǒng)發(fā)送生日祝福郵件。將最新活動和優(yōu)惠以郵件的形式告知會員。通常把處理用戶請求郵件發(fā)送請求的郵件服務器稱為服務器。提供了加密的協(xié)議被稱為。 時間:2017年06月07日星期三說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學示例源碼:無個人學習源碼:https://github.com/zcc...
閱讀 1308·2019-08-30 15:44
閱讀 1979·2019-08-30 13:49
閱讀 1651·2019-08-26 13:54
閱讀 3484·2019-08-26 10:20
閱讀 3239·2019-08-23 17:18
閱讀 3294·2019-08-23 17:05
閱讀 2130·2019-08-23 15:38
閱讀 1012·2019-08-23 14:35