JavaWeb - 验证码

  1. 为什么要学习验证码?
    1、可以防止恶意破解密码、刷票、论坛灌水。
    2、有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试。
    3、实际上用验证码是现在很多网站通行的方式,我们利用比较简易的方式实现了这个功能。
  2. 验证码实现的方式
    1、字母数字混合验证码
    import javax.imageio.ImageIO;
    import javax.servlet.http.HttpServletResponse;
    import java.awt.*;
    import java.awt.font.FontRenderContext;
    import java.awt.geom.Rectangle2D;
    import java.awt.image.BufferedImage;
    import java.util.Random;
     
    /**
     * 此方法用户产生随机数-字母和数字
     * @return
     */
    private static char randomChar(){
        //1:定义验证需要的字母和数字
        String string = "QWERTYUIOPASDFGHJKLZXCVBNM0123456789";
        //2:定义随机对象
        Random random = new Random();
        return string.charAt(random.nextInt(string.length()));
    }
    /**
     * 字母数字混合验证码
     * @param response
     * @return
     */
    public static String drawImage(HttpServletResponse response){
        //1:定义以字符串的拼接的StringBuilder
        StringBuilder builder = new StringBuilder();
        //准备产生4个字符串的随机数
        for(int i=0;i<4;i++){
            builder.append(randomChar());
        }
        String code = builder.toString();
    
        //2:定义图片的宽度和高度
        int width = 70;
        int height = 25;
        //简历bufferedImage对象,制定图片的长度和宽度以及色彩
        BufferedImage bi = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
        //3:获取到 Graphics2D 绘制对象,开始绘制验证码
        Graphics2D g = bi.createGraphics();
        //4:设置文字的字体和大小
        Font font = new Font("微软雅黑",Font.PLAIN,20);
        //设置字体的颜色
        Color color = new Color(0,0,0);
        //设置字体
        g.setFont(font);
        //设置颜色
        g.setColor(color);
        //设置背景
        g.setBackground(new Color(226,226,240));
        //开始绘制对象
        g.clearRect(0,0,width,height);
        //绘制形状,获取矩形对象
        FontRenderContext context = g.getFontRenderContext();
        Rectangle2D bounds = font.getStringBounds(code,context);
        //计算文件的坐标和间距
        double x = (width - bounds.getWidth())/2;
        double y = (height - bounds.getHeight())/2;
        double ascent = bounds.getY();
        double baseY = y - ascent;
        g.drawString(code,(int)x,(int)baseY);
        //结束绘制
        g.dispose();
        try {
            ImageIO.write(bi,"jpg",response.getOutputStream());
            //刷新响应流
            response.flushBuffer();
        }catch(Exception ex){
            ex.printStackTrace();
        }
    
        return code;
    }
    // code.jsp
    
    <%@ page import="com.imooc.code.CaptcahCode" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%
    
        // 清空浏览器缓存,目的是为了清空浏览器的缓存,因为浏览器会对网站的资源文件和图像进行记忆存储,
        // 如果被浏览器加载过的图片就记忆起来,记忆以后,
        // 文件就不会和服务器在交互,如果我们验证不清空的话可能会造成一个问题就是:验证刷新以后没有效果。
        response.setHeader("pragma","no-cache");
        response.setHeader("cache-control","no-cache");
        response.setHeader("expires","0");
    
        //2:调用编写的生成验证码的工具
        String code = CaptcahCode.drawImage(response);
        session.setAttribute("code",code);
    
        //3:如何解决getOutputStream异常问题
        out.clear();
        out = pageContext.pushBody();
    %>
    // index.jsp
    
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <!DOCTYPE HTML>
    <html>
      <head>
        <title>java验证码</title>
    	<meta http-equiv="pragma" content="no-cache">
    	<meta http-equiv="cache-control" content="no-cache">
    	<meta http-equiv="expires" content="0">    
      </head>
      <body>
    
         <img src="code.jsp" alt="" id="code">
         <a href="javascript:void(0);" onclick="changeCode()">看不清?点我</a>
         <script>
             
             function changeCode() {
                 document.getElementById("code").src = "code.jsp?d="+new Date().getTime();
             }
    
         </script>
      </body>
    </html>
    2、算术验证码

    import javax.imageio.ImageIO;
    import javax.servlet.http.HttpServletResponse;
    import java.awt.*;
    import java.awt.font.FontRenderContext;
    import java.awt.geom.Rectangle2D;
    import java.awt.image.BufferedImage;
    import java.util.Random;
     
    /**
     * 范围随机颜色
     * @param fc
     * @param bc
     * @return
     */
    public static Color getRandomColor(int fc,int bc){
        //利用随机数
        Random random  = new Random();
        //随机颜色,了解颜色-Color(red,green,blue).rgb三元色 0-255
        if(fc>255)fc = 255;
        if(bc>255)bc = 255;
        int r = fc+random.nextInt(bc-fc);
        int g = fc+random.nextInt(bc-fc);
        int b = fc+random.nextInt(bc-fc);
        return new Color(r,g,b);
    }
    /**
     * 算术表达式验证码
     *
     * 1:干扰线的产生
     * 2: 范围随机颜色,随机数
     *
     * @param response
     * @return
     */
    public static  String drawImageVerificate(HttpServletResponse response){
        //定义验证码的宽度和高度
        int width = 100,height = 30;
        //在内存中创建图片
        BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
        //创建图片的上下文
        Graphics2D g = image.createGraphics();
        //产生随机对象,此随机对象主要用于算术表达式的数字
        Random random = new Random();
        //设置背景
        g.setColor(getRandomColor(240,250));
        //设置字体
        g.setFont(new Font("微软雅黑", Font.PLAIN,22));
        //开始绘制
        g.fillRect(0,0,width,height);
    
        //干扰线的绘制,绘制线条到图片中
        g.setColor(getRandomColor(180,230));
        for(int i=0;i<10;i++){
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int x1 = random.nextInt(60);
            int y1 = random.nextInt(60);
            g.drawLine(x,y,x1,y1);
        }
    
        //开始进行对算术验证码表达式的拼接
        int num1 = (int)(Math.random()*10 + 1);
        int num2 = (int)(Math.random()*10 + 1);
        int fuhao = random.nextInt(3);//产生一个[0,2]之间的随机整数
        //记录符号
        String fuhaostr = null;
        int result = 0;
        switch (fuhao){
            case 0 : fuhaostr = "+";result = num1 + num2;break;
            case 1: fuhaostr = "-";result = num1 - num2;break;
            case 2 : fuhaostr = "*";result = num1 * num2;break;
            //case 3 : fuhaostr = "/";result = num1 / num2;break;
        }
        //拼接算术表达式,用户图片显示。
        String calc = num1 + " " + fuhaostr +" "+ num2 +" = ?";
        //设置随机颜色
        g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));
        //绘制表达式
        g.drawString(calc,5,25);
        //结束绘制
        g.dispose();
        try {
            //输出图片到页面
            ImageIO.write(image,"JPEG",response.getOutputStream());
            return String.valueOf(result);
        }catch (Exception ex){
            ex.printStackTrace();
            return null;
        }
    }
    // code.jsp
    
    <%@ page import="com.imooc.code.CaptcahCode" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%
    
        // 清空浏览器缓存,目的是为了清空浏览器的缓存,因为浏览器会对网站的资源文件和图像进行记忆存储,
        // 如果被浏览器加载过的图片就记忆起来,记忆以后,
        // 文件就不会和服务器在交互,如果我们验证不清空的话可能会造成一个问题就是:验证刷新以后没有效果。
        response.setHeader("pragma","no-cache");
        response.setHeader("cache-control","no-cache");
        response.setHeader("expires","0");
    
        //2:调用编写的生成验证码的工具
        String code = CaptcahCode.drawImageVerificate(response);
        session.setAttribute("code",code);
    
        //3:如何解决getOutputStream异常问题
        out.clear();
        out = pageContext.pushBody();
    %>
    // index.jsp
    
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <!DOCTYPE HTML>
    <html>
      <head>
        <title>java验证码</title>
    	<meta http-equiv="pragma" content="no-cache">
    	<meta http-equiv="cache-control" content="no-cache">
    	<meta http-equiv="expires" content="0">    
      </head>
      <body>
    
         <img src="code.jsp" alt="" id="code">
         <a href="javascript:void(0);" onclick="changeCode()">看不清?点我</a>
         <script>
             
             function changeCode() {
                 document.getElementById("code").src = "code.jsp?d="+new Date().getTime();
             }
    
         </script>
      </body>
    </html>
    3、kcaptcha
    // index.jsp
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>关于验证码框架之---Kaptcha</title>
    </head>
    <body>
        <form action="submit.action">
            <input type="text" name="kaptcha" value="" />
            <img src="http://localhost:8080/imooccode/kaptcha.jpg" />
        </form>
    </body>
    </html>
    // web.xml
    
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
    
        <!--关于kaptcha验证码的配置-->
       <!-- <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>/kaptcha.jpg</url-pattern>
        </servlet-mapping>-->
        <servlet>
            <servlet-name>Kaptcha</servlet-name>
            <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
            <init-param>
                <param-name>kaptcha.border</param-name>
                <param-value>no</param-value>
            </init-param>
            <init-param>
                <param-name>kaptcha.image.width</param-name>
                <param-value>100</param-value>
            </init-param>
            <init-param>
                <param-name>kaptcha.image.height</param-name>
                <param-value>40</param-value>
            </init-param>
            <init-param>
                <param-name>kaptcha.textproducer.font.size</param-name>
                <param-value>28</param-value>
            </init-param>
            <init-param>
                <param-name>kaptcha.textproducer.char.string</param-name>
                <param-value>qwertyuiopasdfghjklzxcvbnm123456789</param-value>
            </init-param>
            <init-param>
                <param-name>kaptcha.textproducer.char.length</param-name>
                <param-value>4</param-value>
            </init-param>
            <init-param>
                <param-name>kaptcha.noise.impl</param-name>
                <param-value>com.google.code.kaptcha.impl.DefaultNoise</param-value>
            </init-param>
            <init-param>
                <param-name>kaptcha.obscurificator.impl</param-name>
                <param-value>com.google.code.kaptcha.impl.FishEyeGimpy</param-value>
            </init-param>
            <init-param>
                <!--session.setAttribute("kcode",生成好的验证码)-->
                <param-name>kaptcha.session.key</param-name>
                <param-value>kcode</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>Kaptcha</servlet-name>
            <url-pattern>/kaptcha.jpg</url-pattern>
        </servlet-mapping>
        <servlet>
            <servlet-name>LoginServlet</servlet-name>
            <servlet-class>com.imooc.code.LoginServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>LoginServlet</servlet-name>
            <url-pattern>/login</url-pattern>
        </servlet-mapping>-->
    
    
    </web-app>
    // 配置详情.txt
    
    Kaptcha是一个基于SimpleCaptcha的验证码开源项目。
    官网地址:http://code.google.com/p/kaptcha/
    
    kaptcha的使用比较方便,只需添加jar包依赖之后简单地配置就可以使用了。kaptcha所有配置都可以通过web.xml来完成,如果你的项目中使用了Spring MVC,那么则有另外的一种方式来实现。
    
    一、简单的jsp-servlet项目
    1.添加jar包依赖
    如果你使用maven来统一管理jar包,则在工程的pom.xml中添加dependency
    Xml代码  收藏代码
    <!-- kaptcha -->
    <dependency>
        <groupId>com.google.code.kaptcha</groupId>
        <artifactId>kaptcha</artifactId>
        <version>2.3.2</version>
    </dependency>
    如果是非maven管理的项目,则直接在官网下载kaptcha的jar包,然后添加到项目lib库中,下载地址:http://code.google.com/p/kaptcha/downloads/list
    
    2.配置web.xml
    上面说了,kaptcha都是在web.xml中配置,我们必须在web.xml中配置kaptcha的servlet,具体如下:
    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>/kaptcha.jpg</url-pattern>
    </servlet-mapping>
    其中servlet的url-pattern可以自定义。
    
    kaptcha所有的参数都有默认的配置,如果我们不显示配置的话,会采取默认的配置。
    如果要显示配置kaptcha,在配置kaptcha对应的Servlet时,在init-param增加响应的参数配置即可。示例如下:
    Xml代码  收藏代码
    <servlet>
        <servlet-name>Kaptcha</servlet-name>
        <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
        <init-param>
            <param-name>kaptcha.image.width</param-name>
            <param-value>200</param-value>
            <description>Width in pixels of the kaptcha image.</description>
        </init-param>
        <init-param>
            <param-name>kaptcha.image.height</param-name>
            <param-value>50</param-value>
            <description>Height in pixels of the kaptcha image.</description>
        </init-param>
        <init-param>
            <param-name>kaptcha.textproducer.char.length</param-name>
            <param-value>4</param-value>
            <description>The number of characters to display.</description>
        </init-param>
        <init-param>
            <param-name>kaptcha.noise.impl</param-name>
            <param-value>com.google.code.kaptcha.impl.NoNoise</param-value>
            <description>The noise producer.</description>
        </init-param>
    </servlet>
    具体的配置参数参见:http://code.google.com/p/kaptcha/wiki/ConfigParameters
    
    Constant	描述	默认值
    kaptcha.border	图片边框,合法值:yes , no	yes
    kaptcha.border.color	边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue.	black
    kaptcha.border.thickness	边框厚度,合法值:>0	1
    kaptcha.image.width	图片宽	200
    kaptcha.image.height	图片高	50
    kaptcha.producer.impl	图片实现类	com.google.code.kaptcha.impl.DefaultKaptcha
    kaptcha.textproducer.impl	文本实现类	com.google.code.kaptcha.text.impl.DefaultTextCreator
    kaptcha.textproducer.char.string	文本集合,验证码值从此集合中获取	abcde2345678gfynmnpwx
    kaptcha.textproducer.char.length	验证码长度	5
    kaptcha.textproducer.font.names	字体	Arial, Courier
    kaptcha.textproducer.font.size	字体大小	40px
    kaptcha.textproducer.font.color	字体颜色,合法值: r,g,b  或者 white,black,blue.	black
    kaptcha.textproducer.char.space	文字间隔	2
    kaptcha.noise.impl	干扰实现类	com.google.code.kaptcha.impl.DefaultNoise
    kaptcha.noise.color	干扰颜色,合法值: r,g,b 或者 white,black,blue.	black
    kaptcha.obscurificator.impl	图片样式:
    水纹com.google.code.kaptcha.impl.WaterRipple
    鱼眼com.google.code.kaptcha.impl.FishEyeGimpy
    阴影com.google.code.kaptcha.impl.ShadowGimpy
    com.google.code.kaptcha.impl.WaterRipple
    kaptcha.background.impl	背景实现类	com.google.code.kaptcha.impl.DefaultBackground
    kaptcha.background.clear.from	背景颜色渐变,开始颜色	light grey
    kaptcha.background.clear.to	背景颜色渐变,结束颜色	white
    kaptcha.word.impl	文字渲染器
    com.google.code.kaptcha.text.impl.DefaultWordRenderer
    kaptcha.session.key	session key	KAPTCHA_SESSION_KEY
    kaptcha.session.date	session date	KAPTCHA_SESSION_DATE
    
    3.页面调用
    Html代码  收藏代码
    <form action="submit.action">
        <input type="text" name="kaptcha" value="" /><img src="kaptcha.jpg" />
    </form>
    
    4.在submit的action方法中进行验证码校验
    Java代码  收藏代码
    //从session中取出servlet生成的验证码text值
    String kaptchaExpected = (String)request.getSession().getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
    //获取用户页面输入的验证码
    String kaptchaReceived = request.getParameter("kaptcha");
    //校验验证码是否正确
    if (kaptchaReceived == null || !kaptchaReceived.equalsIgnoreCase(kaptchaExpected)){
        setError("kaptcha", "Invalid validation code.");
    }
    注:确保JDK设置了 -Djava.awt.headless=true
    
    5.实现页面验证码刷新
    Html代码  收藏代码
    <img src="kaptcha.jpg" width="200" id="kaptchaImage" title="看不清,点击换一张" />
    <script type="text/javascript">
        $(function() {
            $('#kaptchaImage').click(function() {$(this).attr('src','kaptcha.jpg?' + Math.floor(Math.random() * 100));});
        });
    </script>
    <br /><small>看不清,点击换一张</small>

    4、jcaptcha
  3. 了解验证码功能的实现与原理



  4. kcaptcha 应用版(在2的kcaptcha的基础上)
    // test.jsp
    
    <%--
      Created by IntelliJ IDEA.
      User: Administrator
      Date: 2017/9/8
      Time: 21:10
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>登录</title>
        <style>#code{height:30px;}</style>
    </head>
    <body>
    
    <form action="submit.action">
    
        <p> <input type="text" name="kaptcha" id="code" value="" maxlength="4" placeholder="请输入验证码"/>
        <img src="http://localhost:8080/imooccode/kaptcha.jpg" id="changecode"/>
        </p>
        <p>
        <input type="button" id="login" value="登录">
        </p>
        <div id="result"></div>
    </form>
    
    <script src="js/jquery-1.12.4.min.js" type="text/javascript"></script>
    <script>
    
        $(function(){
            $("#changecode").on("click",function(){
                $(this).attr("src","http://localhost:8080/imooccode/kaptcha.jpg?d="+new Date().getTime());
            });
             //给登录按钮绑定点击事件
            $("#login").on("click",function(){
                //获取用户输入的验证码
                var code = $("#code").val();
                //alert(code);
                var params = {"code":code};
                $.post("http://localhost:8080/imooccode/login",params,function(data){
    //                if(data=="fail"){
    //                     alert("验证码输入有误!");
    //                }
                    if(data=="success"){
                        $("#result").html("验证码输入正确");
                    }else{
                        $("#result").html("验证码输入有误,请重新输入...");
                        $("#code").val("").focus();
                    }
                });
            });
        })
    
    </script>
    
    </body>
    </html>
    package com.imooc.code;
    
    import com.google.code.kaptcha.Constants;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    public class LoginServlet extends HttpServlet {
        public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //设置编码
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
    
            //获取浏览器输出流对象
            PrintWriter out = response.getWriter();
            //获取用户传递过来的验证码
            String code = request.getParameter("code");
            //获取验证码框架产生的验证码(会话中存储的验证码)
            String sessionCode = (String)request.getSession().getAttribute("kcode");
            if(code!=null&sessionCode!=null) {
                //如果用户输入的验证码和产生在服务器端的验证码一致,那么就告诉用户输入正确
                if (code.equalsIgnoreCase(sessionCode)) {
                    //登录逻辑、注册逻辑等相关的业务操作
                    out.print("success");
                } else {
                    out.print("fail");
                }
            }
    
            out.flush();
            out.close();
        }
    
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request,response);
        }
    }

  5. 待更新...
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

放羊的牧码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值