验证码三种实现(一般,依赖颜色,问答)

原来做验证码都是通过patchca 一个类库生成的

今天上信息安全的课的时候 老师提到了原来的学生有做验证码识别的(通过OpenCV)

 

    http://zh.wikipedia.org/wiki/验证码 写道

全自动区分计算机和人类的图灵测试(英语:Completely Automated Public Turing test to tell Computers and Humans Apart,简称CAPTCHA),俗称验证码,是一种区分用户是计算机和人的公共全自动程序。在CAPTCHA测试中,作为服务器的计算机会自动生成一个问题由用户来解答。这个问题可以由计算机生成并评判,但是必须只有人类才能解答。由于计算机无法解答CAPTCHA的问题,所以回答出问题的用户就可以被认为是人类。

 

     做网页用验证码的目的之一是为了对用户密码进行暴力破解.当然还有其他的目的.

 

然后我想无聊做做就做做吧 空着也空着

我就想到了三个形式的:

  1. 最普通的形式
  2. 依赖颜色的(填写的是指定颜色的验证码)
  3. 问答形式的

先看下实现的图吧:



 最普通的 也就是通过一些线来扰乱视线 没通过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;
	}

}

 

代码欢迎随便使用

如有问题请留言.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值