原来做验证码都是通过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;
}
}
代码欢迎随便使用
如有问题请留言.