JSP 验证码详解

验证码定义:
验证码(Capcha):是一种区分用户是计算机还是人的公共全自动程序。
作用:可以防止恶意破解密码,算票,论坛灌水,有效防止某个黑客对某个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试。
实际上用验证码是现在很多网站通行的方式,我们运用比较简单的方式实现这个功能。
实现步骤:
生成图片的类:
bufferedimage图像数据缓冲区
graphics绘制图片
color获取颜色
random生成随机数
imageio输出图片
生成图片的实现类:ImageServlet
1.定义bufferedimage对象
2.获取craphics对象
3.通过random产生随机验证码信息
4.使用graphics绘制图片
5.记录验证码信息到session中
6.使用imageIO输出图片
    public class ImageServlet extends HttpServlet {
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
            BufferedImage bi = new BufferedImage(68, 22, BufferedImage.TYPE_INT_RGB);
            Graphics g = bi.getGraphics();
            Color c = new Color(200, 150, 255);
            g.setColor(c);
            g.fillRect(0, 0, 68, 22);
            char[] ch = "abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
            Random r = new Random();
            int len = ch.length, index;
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < 4; i++) {
                index = r.nextInt(len);
                g.setColor(new Color(r.nextInt(88), r.nextInt(188), r.nextInt(255)));
                g.drawString(ch[index] + "", (i * 15) + 3, 18);
                sb.append(ch[index]);
            }
            request.getSession().setAttribute("piccode", sb.toString());
            ImageIO.write(bi, "JPG", response.getOutputStream());
        }
    }


校验验证码是否正确:LoginServlet类
1.获取页面验证码
2.获取session保存的验证码
3.比较验证码
4.返回校验结果
    public class LoginServlet extends HttpServlet {
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException{
            String piccode = (String) request.getSession().getAttribute("piccode");
            piccode = piccode.toLowerCase();
            String checkcode = request.getParameter("checkcode").toLowerCase();
            response.setContentType("text/html;charset=gbk");
            PrintWriter out = response.getWriter();
            if(checkcode.equals(piccode)){
                out.println("验证码输入正确!");
            }else{
                out.println("验证码输入错误!!!");
            }
            out.flush();
            out.close();
        }
    }


前台页面的实现:
<script type="text/javascript">
function reloadCode(){
var time = new Date().getTime();
document.getElementByIdx_x("imagecode").src="<%=request.getContextPath() %>/servlet/ImageServlet?d="+time;
}
</script>
<body>
 
    验证码:<input type="text" name="checkcode"/>
    <img alt="验证码" id="imagecode" src="<%=request.getContextPath() %>/servlet/ImageServlet"/>
    <a href="javascript: reloadCode();">看不清楚</a><br>
    <input type="submit" value="提交">
   
  </body>


开源组件实现验证码:
Jcaptcha:一个用来生成图形验证码的java开源组件,使用起来非常方便。谕spring组合使用,可产生多种形式的验证码。
Kaptcha:一个常用使用的验证码生成工具,有了它,你可以生成各种样式的验证码,因为它是可配置的。
使用Jcaptcha开源组件:

首先在web-inf的lib文件夹下添加如下jar包:


然后实现一个servlet:SubmitActionServlet
public class SubmitActionServlet extends HttpServlet
{
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException
  {
    String userCaptchaResponse = request.getParameter("japtcha");
    boolean captchaPassed = SimpleImageCaptchaServlet.validateResponse(request, userCaptchaResponse);
    if (captchaPassed)
      response.getWriter().write("captcha passed");
    else {
      response.getWriter().write("captcha failed");
    }
  }
}


配置web.xml:
  
<servlet>
            <servlet-name>jcaptcha</servlet-name>
            <servlet-class>com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet</servlet-class>
    </servlet>
  <servlet>
    <servlet-name>submit</servlet-name>
    <servlet-class>cn.edu.hpu.SubmitActionServlet</servlet-class>
  </servlet>
    <servlet-mapping>
            <servlet-name>jcaptcha</servlet-name>
            <url-pattern>/jcaptcha.jpg</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
            <servlet-name>submit</servlet-name>
            <url-pattern>/submit.action</url-pattern>
    </servlet-mapping>


最后是index.jsp:
<body>
<h2>Simple Captcha Servlet sample</h2>
t">
     <img src="jcaptcha.jpg" /> <input type="text" name="japtcha" value="" />
     <input type="submit"/>
</body>


开源组件Kaptcha的实现:
首先在web-inf的lib文件夹下添加如下jar包:
kaptcha-2.3.jar
然后配置web.xml:
<servlet>
  <servlet-name>kaptcha</servlet-name>
  <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
  </servlet>
<servlet-mapping>
<servlet-name>kaptcha</servlet-name>
<url-pattern>/randomcode.jpg</url-pattern>
</servlet-mapping>


然后是index.jsp:
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>randomcode</title>
<script type="text/javascript">
function changeR(node){
// 用于点击时产生不同的验证码
node.src = "randomcode.jpg?time="+new Date().getTime() ;
}
</script>
</head>
<body>
<img alt="random" src="randomcode.jpg" οnclick="changeR(this)" style="cursor: pointer;">
<input type="text" name="r">
<input type="submit" value="提交">
</body>


最后是check.jsp:
<body>
<%
// 检查是否是正确的验证码
String k = (String) session
.getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
String str = request.getParameter("r");
if (k.equals(str))
out.print("true");
out.print("</br>");
out.print(k + "---" + str);
%>
</body>


Kaptcha的详细配置:

<servlet>
  <servlet-name>kaptcha</servlet-name>
  <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
  <init-param>
<description>图片边框,合法值:yes , no</description>
<param-name>kaptcha.border</param-name>
<param-value>yes</param-value>
</init-param>
<init-param>
<description>
边框颜色,合法值: r,g,b (and optional alpha) 或者white,black,blue.
</description>
<param-name>kaptcha.border.color</param-name>
<param-value>red</param-value>
</init-param>
<init-param>
<description>边框厚度,合法值:>0</description>
<param-name>kaptcha.border.thickness</param-name>
<param-value>1</param-value>
</init-param>
<init-param>
<description>图片宽 200</description>
<param-name>kaptcha.image.width</param-name>
<param-value>200</param-value>
</init-param>
<init-param>
<description>图片高 50</description>
<param-name>kaptcha.image.height</param-name>
<param-value>50</param-value>
</init-param>
<init-param>
<description>图片实现类</description>
<param-name>kaptcha.producer.impl</param-name>
<param-value>
com.google.code.kaptcha.impl.DefaultKaptcha
</param-value>
</init-param>
<init-param>
<description>文本实现类</description>
<param-name>kaptcha.textproducer.impl</param-name>
<param-value>
com.google.code.kaptcha.text.impl.DefaultTextCreator
</param-value>
</init-param>
<init-param>
<description>文本集合,验证码值从此集合中获取</description>
<param-name>kaptcha.textproducer.char.string</param-name>
<param-value>abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</param-value>
 <!--<param-value>abcde2345678gfynmnpwx</param-value>-->
<!--<param-value>慕课网教程验证码实例</param-value> -->
</init-param>
<init-param>
<description>验证码长度 5</description>
<param-name>kaptcha.textproducer.char.length</param-name>
<param-value>6</param-value>
</init-param>
<init-param>
<description>字体 Arial, Courier</description>
<param-name>kaptcha.textproducer.font.names</param-name>
<param-value>Arial, Courier</param-value>
</init-param>
<init-param>
<description>字体大小 40px.</description>
<param-name>kaptcha.textproducer.font.size</param-name>
<param-value>40</param-value>
</init-param>
<init-param>
<description>
字体颜色,合法值: r,g,b 或者 white,black,blue.
</description>
<param-name>kaptcha.textproducer.font.color</param-name>
<param-value>black</param-value>
</init-param>
<init-param>
<description>文字间隔 2</description>
<param-name>kaptcha.textproducer.char.space</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<description>干扰实现类</description>
<param-name>kaptcha.noise.impl</param-name>
<param-value>
<!-- com.google.code.kaptcha.impl.NoNoise -->
com.google.code.kaptcha.impl.DefaultNoise
</param-value>
</init-param>
<init-param>
<description>
干扰颜色,合法值: r,g,b 或者 white,black,blue.
</description>
<param-name>kaptcha.noise.color</param-name>
<param-value>black</param-value>
</init-param>
<init-param>
<description>
图片样式: 水纹com.google.code.kaptcha.impl.WaterRipple
鱼眼com.google.code.kaptcha.impl.FishEyeGimpy
阴影com.google.code.kaptcha.impl.ShadowGimpy
</description>
kaptcha.obscurificator.impl
<param-value>
com.google.code.kaptcha.impl.WaterRipple
</param-value>
</init-param>
<init-param>
<description>背景实现类</description>
<param-name>kaptcha.background.impl</param-name>
<param-value>
com.google.code.kaptcha.impl.DefaultBackground
</param-value>
</init-param>
<init-param>
<description>背景颜色渐变,开始颜色</description>
<param-name>kaptcha.background.clear.from</param-name>
<param-value>blue</param-value>
</init-param>
<init-param>
<description>背景颜色渐变,结束颜色</description>
<param-name>kaptcha.background.clear.to</param-name>
<param-value>white</param-value>
</init-param>
<init-param>
<description>文字渲染器</description>
<param-name>kaptcha.word.impl</param-name>
<param-value>
com.google.code.kaptcha.text.impl.DefaultWordRenderer
</param-value>
</init-param>
<init-param>
<description>
session中存放验证码的key键
</description>
<param-name>kaptcha.session.key</param-name>
<param-value>KAPTCHA_SESSION_KEY</param-value>
</init-param>
<init-param>
<description>
The date the kaptcha is generated is put into the
HttpSession. This is the key value for that item in the
session.
</description>
<param-name>kaptcha.session.date</param-name>
<param-value>KAPTCHA_SESSION_DATE</param-value>
</init-param>
  </servlet>

几种效果展示:


中文验证码的实现:
kaptcha自身就有实现中文验证码的类,但是这个方法会出现乱码,这里可以对文本实现类进行重写;

public class ChineseText extends Configurable implements TextProducer {
        public String getText() {
            int length = getConfig().getTextProducerCharLength();
            String finalWord = "", firstWord = "";
            int tempInt = 0;
            String[] array = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
                    "a", "b", "c", "d", "e", "f"};
            Random rand = new Random();
            for (int i = 0; i < length; i++) {
                switch (rand.nextInt(array.length)) {
                    case 1:
                        tempInt = rand.nextInt(26) + 65;
                        firstWord = String.valueOf((char) tempInt);
                        break;
                    case 2:
                        int r1,
                                r2,
                                r3,
                                r4;
                        String strH,
                                strL;// high&low
                        r1 = rand.nextInt(3) + 11; // 前闭后开[11,14)Disconnected from the target VM, address: '127.0.0.1:60560', transport: 'socket'


                        if (r1 == 13) {
                            r2 = rand.nextInt(7);
                        } else {
                            r2 = rand.nextInt(16);
                        }
                        r3 = rand.nextInt(6) + 10;
                        if (r3 == 10) {
                            r4 = rand.nextInt(15) + 1;
                        } else if (r3 == 15) {
                            r4 = rand.nextInt(15);
                        } else {
                            r4 = rand.nextInt(16);
                        }
                        strH = array[r1] + array[r2];
                        strL = array[r3] + array[r4];
                        byte[] bytes = new byte[2];
                        bytes[0] = (byte) (Integer.parseInt(strH, 16));
                        bytes[1] = (byte) (Integer.parseInt(strL, 16));
                        firstWord = new String(bytes);
                        break;
                    default:
                        tempInt = rand.nextInt(10) + 48;
                        firstWord = String.valueOf((char) tempInt);
                        break;
                }
                finalWord += firstWord;
            }
            return finalWord;
        }
    }

然后再web.xml中配置:

<init-param>
<description>文本实现类</description>
<param-name>kaptcha.textproducer.impl</param-name>
<param-value>
cn.edu.hpu.ChineseText
</param-value>
</init-param>

如果想使用自定义中文,可以将类中的注释部分的getText方法,或者直接在web.xml的字体集中添加文字。
特别注意:这里由于是中文验证码,所以字体绝对不能使用Arial。
为了实现验证,在index.jsp中,给from添加method="post",并把编码方式改为utf-8,在check.jsp中添加str = new String(str.getBytes("iso-8859-1"),"utf-8");来实现比较。
实现效果:


kaptcha组件扩展:
实现运算式的验证码:

public class KaptchaServlet extends HttpServlet implements Servlet {
        private Properties props;
        private Producer kaptchaProducer;
        private String sessionKeyValue;

        public KaptchaServlet() {
            this.props = new Properties();
            this.kaptchaProducer = null;
            this.sessionKeyValue = null;
        }

        public void init(ServletConfig conf) throws ServletException {
            super.init(conf);
            ImageIO.setUseCache(false);
            Enumeration initParams = conf.getInitParameterNames();
            while (initParams.hasMoreElements()) {
                String key = (String) initParams.nextElement();
                String value = conf.getInitParameter(key);
                this.props.put(key, value);
            }
            Config config = new Config(this.props);
            this.kaptchaProducer = config.getProducerImpl();
            this.sessionKeyValue = config.getSessionKey();
        }

        public void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            resp.setDateHeader("Expires", 0L);
            resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
            resp.addHeader("Cache-Control", "post-check=0, pre-check=0");
            resp.setHeader("Pragma", "no-cache");
            resp.setContentType("image/jpeg");
            String capText = this.kaptchaProducer.createText();
            String s1 = capText.substring(0, 1);
            String s2 = capText.substring(1, 2);
            int i = (int) (Math.random() * 10) % 3 + 1;
            char flag = 0;
            int r = 0;
            switch (i) {
                case 1:
                    flag = '+';
                    r = Integer.valueOf(s1).intValue() + Integer.valueOf(s2).intValue();
                    break;
                case 2:
                    flag = '-';
                    r = Integer.valueOf(s1).intValue() - Integer.valueOf(s2).intValue();
                    break;
                case 3:
                    flag = '*';
                    r = Integer.valueOf(s1).intValue() * Integer.valueOf(s2).intValue();
                    break;
                default:
                    break;
            }
            req.getSession().setAttribute(this.sessionKeyValue, String.valueOf(r));
            BufferedImage bi = this.kaptchaProducer.createImage(s1 + flag + s2 + "=?");
            ServletOutputStream out = resp.getOutputStream();
            ImageIO.write(bi, "jpg", out);
            try {
                out.flush();
            } finally {
                out.close();
            }
        }
    }

只需在web.xml文件中修改:

<servlet>
  <servlet-name>kaptcha</servlet-name>
  <servlet-class>cn.edu.hpu.KaptchaServlet</servlet-class>

<init-param>
<description>验证码长度 5</description>
<param-name>kaptcha.textproducer.char.length</param-name>
<param-value>2</param-value>
</init-param>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值