原来做验证码都是通过patchca 一个类库生成的
今天上信息安全的课的时候 老师提到了原来的学生有做验证码识别的(通过OpenCV)
http://zh.wikipedia.org/wiki/验证码 写道
全自动区分计算机和人类的图灵测试(英语:Completely Automated Public Turing test to tell Computers and Humans Apart,简称CAPTCHA),俗称验证码,是一种区分用户是计算机和人的公共全自动程序。在CAPTCHA测试中,作为服务器的计算机会自动生成一个问题由用户来解答。这个问题可以由计算机生成并评判,但是必须只有人类才能解答。由于计算机无法解答CAPTCHA的问题,所以回答出问题的用户就可以被认为是人类。
做网页用验证码的目的之一是为了对用户密码进行暴力破解.当然还有其他的目的.
然后我想无聊做做就做做吧 空着也空着
我就想到了三个形式的:
- 最普通的形式
- 依赖颜色的(填写的是指定颜色的验证码)
- 问答形式的
先看下实现的图吧:
最普通的 也就是通过一些线来扰乱视线 没通过Path(Path好像是android的API里的吧..)之类的进行弧度显示 这个普通的没做颜色处理(都是很深的颜色) 要处理的可以自己修改
输入的字符是指定颜色的(指定的颜色就是下面那一行的颜色 之所以要画在图上 是发现网页上显示的和图上的会有差别)
这边为了能更好让用户看出来 所以要输入的验证码的颜色都是很深的
R:0-50 G:0-50 B:0-50 个数随机(最少1个 最多全部都是) 可以自己再设定下验证码的颜色以免太容易被识别出来
问答形式的 最多只能45个字符 每行15个 可以3行(更多就显示不出来了... ...自己设定下宽高)
具体的实现如下
都是蛮简单的 (我把一些本来应该作为常量的放在了方法里面 我就不移动了)
package org.cc.servlet; // 省略了import 下同 /** * 这是最基本的验证码形式 * 也就是一排数字和字母的组合 * 不做验证的处理了 定义一个属性放在session(每个连接一个session 不用担心数据共享的问题) * 运行后控制台直接打印验证码 * @author cc fairjm * {@link http://fair-jm.iteye.com/} * */ @WebServlet(name="verifyCode",urlPatterns={"/verifyCode"}) public class VerifyCode extends HttpServlet { // 作为验证码的字符 private final char[] codeSequence = {'A','B','C','D','E','F','G','H','I' ,'J','K','L','M','N','O','P','Q','R' ,'S','T','U','V','W','X','Y','Z','0' ,'1','2','3','4','5','6','7','8','9'}; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 图像的高度 int height = 60; // 图像的宽度 int width = 200; // 字体大小 int fontSize=40; //字体高度 int fontHeight=-1; // 创建一个随机数生成器类。 Random random = new Random(); random.setSeed(new Date().getTime()); //显示的验证码字符数量 int number=random.nextInt(3)+4; BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = buffImg.createGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, width, height); // 创建字体,字体的大小应该根据图片的高度来定。 Font font = new Font("consolas", Font.BOLD,fontSize); // 设置字体 g.setFont(font); FontMetrics fm=g.getFontMetrics(); // 得到高度 fontHeight=fm.getHeight(); // 画边框。 g.setColor(Color.BLACK); g.drawRect(0, 0, width - 1, height - 1); // 随机产生40条干扰线,使图象中的认证码不易被其它程序探测到。 for (int i = 0; i < 40; i++) { Color color=new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)); int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(width/2); int yl = random.nextInt(height/2); g.setColor(color); g.drawLine(x, y, x + xl, y + yl); } StringBuffer randomCode = new StringBuffer(); int red = 0, green = 0, blue = 0; for (int i = 0; i < number; i++) { // 得到随机产生的验证码数字。 String strRand = String.valueOf(codeSequence[random.nextInt(36)]); // 产生随机的颜色分量来构造颜色值,这样输出的每位数字的颜色值都将不同。 red = random.nextInt(50); green = random.nextInt(50); blue = random.nextInt(50); // 用随机产生的颜色将验证码绘制到图像中。 g.setColor(new Color(red, green, blue)); g.drawString(strRand, width/(number+1)*(i+1),fontHeight+random.nextInt(fontHeight)/5); // 将产生的四个随机数组合在一起。 randomCode.append(strRand); } HttpSession session = req.getSession(); session.setAttribute("randomCode", randomCode.toString()); // 禁止图像缓存。 resp.setHeader("Pragma", "no-cache"); resp.setHeader("Cache-Control", "no-cache"); resp.setDateHeader("Expires", 0); resp.setContentType("image/jpeg"); // 将图像输出到Servlet输出流中。 ServletOutputStream sos = resp.getOutputStream(); ImageIO.write(buffImg, "jpeg", sos); sos.close(); System.out.println("I:"+session.getAttribute("randomCode")); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req, resp); } }
颜色:
package org.cc.servlet; /** * 指定颜色的 * @author cc fairjm * {@link http://fair-jm.iteye.com/} * */ @WebServlet(name="verifyColor",urlPatterns={"/verifyColor"}) public class VerifyColor extends HttpServlet { // 作为验证码的字符 private final char[] codeSequence = {'A','B','C','D','E','F','G','H','I' ,'J','K','L','M','N','O','P','Q','R' ,'S','T','U','V','W','X','Y','Z','0' ,'1','2','3','4','5','6','7','8','9'}; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 图像的高度 int height = 60; // 图像的宽度 int width = 200; // 字体大小 int fontSize=40; //字体高度 int fontHeight=-1; // 创建一个随机数生成器类。 Random random = new Random(); random.setSeed(new Date().getTime()); //显示的验证码字符数量 int number=random.nextInt(6)+4; BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = buffImg.createGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, width, height); // 创建字体,字体的大小应该根据图片的高度来定。 Font font = new Font("consolas", Font.BOLD,fontSize); // 设置字体 g.setFont(font); FontMetrics fm=g.getFontMetrics(); // 得到高度 fontHeight=fm.getHeight(); // 画边框。 g.setColor(Color.BLACK); g.drawRect(0, 0, width - 1, height - 1); Color usedColor=new Color(random.nextInt(100),random.nextInt(100),random.nextInt(100)); StringBuffer randomCode = new StringBuffer(); for (int i = 0; i < number; i++) { int red = 0, green = 0, blue = 0; // 得到随机产生的验证码数字。 String strRand = String.valueOf(codeSequence[random.nextInt(36)]); if(random.nextBoolean()||i==number/2){ g.setColor(usedColor); g.drawString(strRand, width/(number+1)*(i+1),fontHeight); randomCode.append(strRand); continue; } do{ red = random.nextInt(50)+200; green = random.nextInt(50)+200; blue = random.nextInt(50)+200; }while( Math.abs(red-usedColor.getRed())<20&& Math.abs(green-usedColor.getGreen())<20&& Math.abs(blue-usedColor.getBlue())<20); g.setColor(new Color(red,green,blue)); g.drawString(strRand, width/(number+1)*(i+1),fontHeight); } g.setColor(usedColor); g.fillRect(0, fontHeight, width, height-fontHeight); // 随机产生40条干扰线,使图象中的认证码不易被其它程序探测到。 for (int i = 0; i < 40; i++) { Color color=new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)); int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(width/2); int yl = random.nextInt(height/2); g.setColor(color); g.drawLine(x, y, x + xl, y + yl); } HttpSession session = req.getSession(); session.setAttribute("randomCode", randomCode.toString()); // 禁止图像缓存。 resp.setHeader("Pragma", "no-cache"); resp.setHeader("Cache-Control", "no-cache"); resp.setDateHeader("Expires", 0); resp.setContentType("image/jpeg"); // 将图像输出到Servlet输出流中。 ServletOutputStream sos = resp.getOutputStream(); ImageIO.write(buffImg, "jpeg", sos); sos.close(); System.out.println("color:"+session.getAttribute("randomCode")); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req, resp); } }
package org.cc.servlet; /** * 这个就是指定问题的了... * @author cc fairjm * {@link http://fair-jm.iteye.com/} * */ @WebServlet(name="verifyQuestion",urlPatterns={"/verifyQuestion"}) public class VerifyQuestion extends HttpServlet { private static final List<Question> ques=new ArrayList<Question>(); /* * 如果要用数据库 如下 private static Connection conn; // 以下代码会在类的初始化过程中被执行(类只会被初始化一次除非卸载或者容器关闭了) // 也可以放在类的构造方法中 static{ try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } try { conn=DriverManager.getConnection("数据库地址", "user", "password"); System.out.println(conn); } catch (SQLException e) { e.printStackTrace(); } 进行list的赋值操作 } */ public VerifyQuestion(){ ques.add(new Question("这是第一个问题", "第一个问题的答案")); ques.add(new Question("校名的英文缩写", "zjut")); ques.add(new Question("问题xxxxxxxxxxxxxxxxxxxxxxxxx", "xx")); ques.add(new Question("问题xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "xx")); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 图像的高度 int height = 65; // 图像的宽度 int width = 200; // 字体大小 int fontSize=15; //字体高度 int fontHeight=-1; //每行多少字 int wordsOfRow=15; // 创建一个随机数生成器类。 Random random = new Random(); random.setSeed(new Date().getTime()); int use=random.nextInt(ques.size()); Question usedQuestion=ques.get(use); BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = buffImg.createGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, width, height); // 创建字体 自行调整本机有的字体 Font font = new Font("微软雅黑", Font.BOLD,fontSize); // 设置字体 g.setFont(font); FontMetrics fm=g.getFontMetrics(); // 得到高度 fontHeight=fm.getHeight(); // 画边框。 g.setColor(Color.BLACK); g.drawRect(0, 0, width - 1, height - 1); String question=usedQuestion.getQuestion(); int rows=question.length()/wordsOfRow; rows=rows==0?1:rows; // 没做处理 字数太多的话会画到下面去 for(int i=0;i<rows;i++){ int last=i*wordsOfRow+wordsOfRow; if(i*wordsOfRow+10>question.length()){ last=question.length(); } g.drawString(question.substring(i*wordsOfRow,last), 10,fontHeight*(i+1)); } HttpSession session = req.getSession(); session.setAttribute("randomCode", usedQuestion.getAnswer()); // 禁止图像缓存。 resp.setHeader("Pragma", "no-cache"); resp.setHeader("Cache-Control", "no-cache"); resp.setDateHeader("Expires", 0); resp.setContentType("image/jpeg"); // 将图像输出到Servlet输出流中。 ServletOutputStream sos = resp.getOutputStream(); ImageIO.write(buffImg, "jpeg", sos); sos.close(); System.out.println("answer:"+session.getAttribute("randomCode")); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req, resp); } } // entity class Question implements Serializable{ private static final long serialVersionUID = 1L; private String question; private String answer; public Question(String question, String answer) { super(); this.question = question; this.answer = answer; } public String getAnswer() { return answer; } public void setAnswer(String answer) { this.answer = answer; } public String getQuestion() { return question; } public void setQuestion(String question) { this.question = question; } }
代码欢迎随便使用
如有问题请留言.