千里冰封
JAVA 浓香四溢
posts - 151,comments - 2801,trackbacks - 0

有时候在我们的网络应用中,防止程序自动登录搞破坏,我们一般都会加上验证码,这些验证码一般来说都是由人来识别的,当然,如果验证码很有规律,或者说很清楚,漂亮,那么也是可能被程序识别的,我以前就识别过某网站的验证码,因为比较有规律,所以被识别了,并且识别率达到99%左右,其实我们可以制作很复杂一点的验证码,添加一些干扰的线条或者字体变形,使程序识别的难度加大,这样,我们的目的也就达到了.

下面是生成的图片:


代码如下,JSP代码

<%@page contentType="image/jpeg"%>
<%@page pageEncoding="UTF-8"%>
<%@ page import="java.awt.*,javax.imageio.*,java.io.*,java.util.*,java.awt.image.*" %>
<%--
The taglib directive below imports the JSTL library. If you uncomment it,
you must also add the JSTL library to the project. The Add Library action
on Libraries node in Projects view can be used to add the JSTL 
1.1 library.
--%>
<%--
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 
--%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%!String s="";%>
<%
java.util.List
<String> fonts=new ArrayList<String>();
GraphicsEnvironment.getLocalGraphicsEnvironment().preferLocaleFonts();
String[] names
=GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(Locale.CHINA);
for(String s:names){
    
char c=s.charAt(0);
    
if(Character.isLowerCase(c)||Character.isUpperCase(c)){
        
    }
else{
        fonts.add(s);
    }
}
BufferedImage bi
=new BufferedImage(200,50,BufferedImage.TYPE_INT_RGB);
Graphics2D g
=bi.createGraphics();
char[] cs={'0','1','2','3','4','5','6','7','8','9'};
char[] use=new char[4];
g.setColor(
new Color(240,240,240));
g.fillRect(
0,0,200,50);
for(int i=0;i<4;i++){
    Point p
=new Point(5+(i*((int)(Math.random()*10)+40)),40);
    
int size=0;
    
int[] sizes=new int[20];
    
for(int j=0;j<20;j++){
        sizes[j]
=30+j;
    }
    size
=sizes[(int)(Math.random()*sizes.length)];
    
int face=0;
    
if(Math.random()*10>5){
        face
=Font.BOLD;
    }
else{
        face
=Font.ITALIC;
    }
    use[i]
=cs[(int)(Math.random()*cs.length)];
    g.setPaint(
new GradientPaint(p.x,p.y,new Color((int)(Math.random()*256),0,(int)(Math.random()*256)),
            p.x,p.y
-size,new Color((int)(Math.random()*256),(int)(Math.random()*256),(int)(Math.random()*256))));
    g.setFont(
new Font(fonts.get((int)(Math.random()*fonts.size())),face,size));
    g.drawString(
""+use[i],p.x,p.y);
}
s
=new String(use);
session.setAttribute(
"code", s);
g.setPaint(
null);
for(int i=0;i<4;i++){
    g.setColor(
new Color((int)(Math.random()*0x00FFFFFFF)));
    g.drawLine((
int)(Math.random()*200),(int)(Math.random()*50),(int)(Math.random()*200),(int)(Math.random()*50));
}
Random random 
= new Random();
for (int i=0;i<88;i++) {
    
int x = random.nextInt(200);
    
int y = random.nextInt(50);
    g.setColor(
new Color((int)(Math.random()*0x00FFFFFFF)));
    g.setStroke(
new BasicStroke((float)(Math.random()*3)));
    g.drawLine(x,y,x,y);
}
OutputStream ot
=response.getOutputStream();
ImageIO.write(bi,
"JPEG",ot);
g.dispose();
ot.close();
%>

以下是Servlet代码
/*
 * Code.java
 *
 * Created on 2007年9月21日, 下午12:08
 
*/

package com.hadeslee;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import javax.imageio.ImageIO;

import javax.servlet.*;
import javax.servlet.http.*;

/**
 *
 * 
@author lbf
 * 
@version
 
*/
public class Code extends HttpServlet {
    
    
/** Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * 
@param request servlet request
     * 
@param response servlet response
     
*/
    
private List<String> fonts=new ArrayList<String>();
    
public Code(){
        initFonts();
    }
    
private void initFonts(){
        GraphicsEnvironment.getLocalGraphicsEnvironment().preferLocaleFonts();
        String[] names
=GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(Locale.CHINA);
        
for(String s:names){
            
char c=s.charAt(0);
            
if(Character.isLowerCase(c)||Character.isUpperCase(c)){
                
            }
else{
                fonts.add(s);
            }
        }
    }
    
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    
throws ServletException, IOException {
        response.setContentType(
"image/jpeg;charset=UTF-8");
        OutputStream out
=response.getOutputStream();
        BufferedImage bi
=new BufferedImage(200,50,BufferedImage.TYPE_INT_RGB);
        Graphics2D g
=bi.createGraphics();
        
char[] cs={'0','1','2','3','4','5','6','7','8','9'};
        
char[] use=new char[4];
        g.setColor(
new Color(240,240,240));
        g.fillRect(
0,0,200,50);
        
for(int i=0;i<4;i++){
            Point p
=getPoint(i);
            
int size=getSize();
            use[i]
=cs[(int)(Math.random()*cs.length)];
           
// g.setColor(new Color((int)(Math.random()*256),0,(int)(Math.random()*256)));
            g.setPaint(getPaint(p,size));
            g.setFont(
new Font(fonts.get((int)(Math.random()*fonts.size())),getFace(),size));
            g.drawString(
""+use[i],p.x,p.y);
        }
        g.setStroke(
new BasicStroke(1.0f));
        g.setPaint(
null);
        
for(int i=0;i<4;i++){
            g.setColor(
new Color((int)(Math.random()*0x00FFFFFFF)));
            g.drawLine((
int)(Math.random()*200),(int)(Math.random()*50),(int)(Math.random()*200),(int)(Math.random()*50));
        }
        Random random 
= new Random();
        
for (int i=0;i<88;i++) {
            
int x = random.nextInt(200);
            
int y = random.nextInt(50);
            g.setColor(
new Color((int)(Math.random()*0x00FFFFFFF)));
            g.setStroke(getStroke());
            g.drawLine(x,y,x,y);
        }
        ImageIO.write(bi,
"JPEG",out);
        out.close();
        g.dispose();
    }
    
private Stroke getStroke(){
      BasicStroke bs
=new BasicStroke((float)(Math.random()*3));
      
return bs;
    }
    
private Point getPoint(int index){
        
return new Point(5+(index*((int)(Math.random()*10)+40)),40);
    }
    
private Paint getPaint(Point p,int size){
        GradientPaint gp
=new GradientPaint(p.x,p.y,new Color((int)(Math.random()*256),0,(int)(Math.random()*256)),
                p.x,p.y
-size,new Color((int)(Math.random()*256),(int)(Math.random()*256),(int)(Math.random()*256)));
        
return gp;
    }
    
private int getFace(){
        
if(Math.random()*10>5){
            
return Font.BOLD;
        }
else{
            
return Font.ITALIC;
        }
    }
    
private int getSize(){
        
int[] sizes=new int[20];
        
for(int i=0;i<20;i++){
            sizes[i]
=30+i;
        }
        
return sizes[(int)(Math.random()*sizes.length)];
    }
    
    
// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** Handles the HTTP <code>GET</code> method.
     * 
@param request servlet request
     * 
@param response servlet response
     
*/
    
protected void doGet(HttpServletRequest request, HttpServletResponse response)
    
throws ServletException, IOException {
        processRequest(request, response);
    }
    
    
/** Handles the HTTP <code>POST</code> method.
     * 
@param request servlet request
     * 
@param response servlet response
     
*/
    
protected void doPost(HttpServletRequest request, HttpServletResponse response)
    
throws ServletException, IOException {
        processRequest(request, response);
    }
    
    
/** Returns a short description of the servlet.
     
*/
    
public String getServletInfo() {
        
return "Short description";
    }
    
// </editor-fold>
}


在这里我们先得到了服务器所在的系统的字体,并用这些字体生成不同的字符,然后再随机设大小,随机变形,然后为字体加上渐变,并给整个图片添加干扰线条以及干扰点.让程序识别的难度加大.

呵呵,我们可以把它改成字母或者中文的验证,道理都是一样的,只不过在生成的时候,不一定用数字了,而是用所有可以输入的文字.这样,被程序识别的可能又小了.


尽管千里冰封
依然拥有晴空

你我共同品味JAVA的浓香.
posted on 2007-09-21 13:05 千里冰封 阅读(2211) 评论(10)  编辑  收藏 所属分类: JAVAEE

FeedBack:
# re: 随机数字验证码的生成
2007-09-21 14:06 | sitinspring
作个记号,用到时再来细看.  回复  更多评论
  
# re: 随机数字验证码的生成
2007-09-21 16:06 | zht
还有另外一种方式是根据随机数从服务器上取图片然后再画出来,
感觉这样数字的风格可以随时换  回复  更多评论
  
# re: 随机数字验证码的生成[未登录]
2007-09-21 17:00 | a
good  回复  更多评论
  
# re: 随机数字验证码的生成[未登录]
2007-09-22 09:26 | quaff
thanks  回复  更多评论
  
# re: 随机数字验证码的生成
2007-09-22 21:45 | cocobear
可不可以写一个识别你这个验证码的程序呢?呵呵  回复  更多评论
  
# re: 随机数字验证码的生成
2007-09-23 14:14 | Alexander.Yu
不错...强啊.  回复  更多评论
  
# re: 随机数字验证码的生成
2007-09-27 17:16 | 彭俊
我也想听听你关于如何识别验证码的基本思路,没有干扰也好。请教要如何识别呢?  回复  更多评论
  
# re: 随机数字验证码的生成
2007-09-27 17:27 | 千里冰封
@彭俊
最基本的思路就是比对,先提取出来字模,然后再比对就可以了  回复  更多评论
  
# re: 随机数字验证码的生成
2007-09-27 17:37 | 彭俊
@千里冰封
抽点时间写写这个内容吧 呵呵
这方面接触的比较少 简单的说一下没有感觉啊
来点直接的Code,肯定有不少人期待呢
当然我也会取search一下先做做功课的
先谢谢了  回复  更多评论
  
# re: 随机数字验证码的生成
2007-09-27 17:47 | 千里冰封
@彭俊
呵呵,好吧,我就把去年写的拿出来分享一下  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: