`

[带菜鸟飞]验证码功能实现

 
阅读更多

验证码一般用于登录功能,其实现一般分为两种,js验证码生成和服务器验证码生成。

js的生成也就是使用js的2D功能画出验证码,这种方法实现起来只要调用几个js插件就可以快速生成,但缺点是,如果有人通过更改浏览器js来绕过验证,这验证码的防线就是一种摆设了。

 

至于服务器的验证码生成要安全的多。其原理也不复杂。

1.在打开登录页面时,通过加载图片元素标签img的src属性可再发出一个请求到后台。

2.在这个请求中可以在服务器中生成一个随机验证字符串并放置于session中。

3.利用java中的2d功能把字符串生成一个图片二进制,并在图片中加入杂波和着色等等。

4.请求返回图片流输出时,把生成后的图片二进制流输出即可。

5.登录验证时,将请求参数中的验证码与session中保存的验证时进行比较验证,无论验证成功与否均在方法最后清除session中的验证码。

 

开始编码,就以上面的步骤来一步步的写

1.先写html页面

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>    
    <title>token</title>
    <script type="text/javascript">
      function changeImage(imageComponent){
        var time = new Date().getTime();
      	imageComponent.src = "${pageContext.request.contextPath}/characters.jpg?" + time;
      }
    </script>
 </head>
  
  <body>
  	<form method="post" action="next.jsp">
  		username:<input type="text" name="username" />
  		password:<input type="password" name="password" />
  		<input type="text" name="token" />
  		<input type="submit" value="login" />
    <img onclick="changeImage(this)" src="${pageContext.request.contextPath}/characters.jpg" />
    </form>
  </body>
</html>

 

 这里可以看到,在这个页面中有三个输入框,一个用户名,一个密码,还有一个验证码。最后还有一个图片标签。地址就是要生成验证码图片的请求。

加入了一个js方法,就是在点击验证码图片时可以换一个验证码。

这个不用讲,没什么好说的。

 

2.要处理请求就要先给个请求的处理机制。这里用xml配个servlet来解决

 

	<servlet>
		<servlet-name>ImageTokenServlet</servlet-name>
		<servlet-class>guides.servlet.imgtoken.ImageTokenServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>ImageTokenServlet</servlet-name>
		<url-pattern>/characters.jpg</url-pattern>
	</servlet-mapping>

 

 

再来看看ImageTokenServlet是怎么来处理的

 

public class ImageTokenServlet extends HttpServlet {
    private int width = 80;
    private int height = 30;
    private String characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private int length = 4;
    
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        //产生tokens并将其保存在当前的会话中        
        TokenUtil.saveToken(request, characters, length);

        //生成图片响应
        TokenUtil.generateTokenImage(response, request.getSession(), width, height);
    }
   
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        doGet(request, response);
    }
    
    }
}

  这里可以看出,servlet也只做了两件事,就是调用了两个工具类方法。至于最上面的属性从名子上就能看出他们的含义了,不解释。

 

再来看TokenUtil.saveToken(request, characters, length);的实现

 

 public static void saveToken(HttpServletRequest request, String characters, int length) {
	Random ran = new Random();
        char[] tokens = new char[length];
        for (int i = 0; i < length; i++) {
            char ch = characters.charAt(ran.nextInt(characters.length()));
            tokens[i] = ch;
        }

        HttpSession session = request.getSession();
        session.setAttribute("token", new String(tokens));
    }
 

 

到目前为止,随机的验证码已经生成了

 

3.看看是怎么把字符串生成一个图片二进制流的

 

 public static void generateTokenImage(HttpServletResponse response, HttpSession session, int width, int height) throws IOException {
        //设置响应内容为图片格式
        response.setContentType("image/jpeg");

        //禁止浏览器缓存
        response.addHeader("pragma", "NO-cache");
		response.addHeader("Cache-Control", "no-cache");
		response.addDateHeader("Expries", 0);

        //绘制图片
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();

        //以下填充背景颜色
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);

        //设置字体颜色
        g.setColor(Color.RED);
        Font font = new Font("Arial", Font.BOLD, 18);
        g.setFont(font);

        //绘制
        String token = (String) session.getAttribute("token");
        g.drawString(token, 5, height - 2);
        g.dispose();

        //发送内容到客户端
        ServletOutputStream out = response.getOutputStream();
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
        encoder.encode(image);
        out.close();
    }

 

 注意,这里不仅是把图片生成了,也同时使用了response的输出流把图片给输出了。

 

4.输入功能已经在上一步给完成了。。。

 

5.登录验证时,再写一个工具方法即可

 

public static boolean isTokenValid(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            return false;
        }

        boolean isLegal = true;
        String[] tokenParams = (String[]) request.getParameterValues("token");
        if (tokenParams == null) {
            isLegal = false;
        } else {
            String token = tokenParams[0];
            if (token == null) {
                isLegal = false;
            } else {
                String sessionToken = (String) session.getAttribute("token");
                if (!token.equalsIgnoreCase(sessionToken)) {
                    isLegal = false;
                }
            }
        }
        //删除会话中的token信息
        session.removeAttribute("token");

        return isLegal;
    }

 这个工具类方法在登录验证时调用一下查看一下返回值即可

 

OK了,整个流程的核心就是这么多。

 

把servlet类和工具类再整理一下,完整点重新贴出来。

 

package guides.servlet.imgtoken;

import guides.servlet.util.TokenUtil;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 用来以图片的形式来生成验证码。
 * 生成验证码后先将其保存到用户的当前会话中,然后在以图片的形式发送到客户端。
 * 验证码的验证要通过TokenFilter来完成。
 * 该Servlet包含如下的初始化参数,来定制验证码的信息:
 * <ul>
 * <li>characters:生成验证码所有的字符序列,默认为数字和字母</li>
 * <li>length:生成的验证码的长度,默认为4位</li>
 * <li>width:验证码图片的显示宽度,默认为80像素</li>
 * <li>height:验证码图片的高度,默认为30像素</li>
 * </ul>
 * 
 * 该Servlet需要在应用的web.xml进行如下部署:
 * <servlet>
 *   <servlet-name>ImageTokenServlet</servlet-name>
 *   <servlet-class>guides.servlet.imgtoken.ImageTokenServlet</servlet-class>
 * </servlet>
 * <servlet-mapping>
 *   <servlet-name>ImageTokenServlet</servlet-name>
 *   <url-pattern>/token/image.jpg</url-pattern>
 * </servlet-mapping>
 * 
 * 然后在客户端网页中进行如下引用:
 * <img src="/yourContextPath/token/image.jpg"></img>
 */
@SuppressWarnings("serial")
public class ImageTokenServlet extends HttpServlet {
    private int width = 80;
    private int height = 30;
    private String characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private int length = 4;
    
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        //产生tokens并将其保存在当前的会话中        
        TokenUtil.saveToken(request, characters, length);

        //生成图片响应
        TokenUtil.generateTokenImage(response, request.getSession(), width, height);
    }
   
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        doGet(request, response);
    }
    
    public void init() {
        String initParam = getInitParameter("characters");
        if (initParam != null) {
            this.characters = initParam;
        }

        initParam = getInitParameter("length");
        if (initParam != null) {
            this.length = Integer.parseInt(initParam);
        }

        initParam = getInitParameter("width");
        if (initParam != null) {
            this.width = Integer.parseInt(initParam);
        }

        initParam = getInitParameter("height");
        if (initParam != null) {
            this.height = Integer.parseInt(initParam);
        }
    }
}

 

 

 

package guides.servlet.util;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**
 * 验证码处理工具类,包含如下功能:
 * 1)产生验证码
 * 2)保存验证码
 * 3)校验验证码
 * 4)生成图像验证码
 */
public class TokenUtil {
	public static final String TOKEN_KEY_NAME = "token";
	public static final String TOKEN_PARAMETER_NAME = "token";
    /**
     * 根据给定的字符序列生成随即的验证码。
     * 
     * @param characters 验证码的字符取值范围
     * @param length 生成的验证码的长度
     * @return 指定长度的验证码字符串
     */
    public static String generateToken(String characters, int length) {
        Random ran = new Random();
        char[] tokens = new char[length];
        for (int i = 0; i < length; i++) {
            char ch = characters.charAt(ran.nextInt(characters.length()));
            tokens[i] = ch;
        }

        return new String(tokens);
    }
   
    /**
     * 生成验证码,并将其保存到当前的会话中。该方法主要应用于Struts1,Servlet,JSP环境。
     * 如果会话不存在,自动创建会话。
     * 
     * @param session 当前的请求对象。
     * @param characters 验证码的字符取值范围
     * @param length 生成的验证码的长度
     */
    public static void saveToken(HttpServletRequest request, String characters, int length) {
        HttpSession session = request.getSession();
        session.setAttribute(TOKEN_KEY_NAME, generateToken(characters, length));
    }
  

    /**
     * 针对当前的请求进行验证码的校验,并且在校验完毕候从会话中清空验证码,将其作废。
     * 该方法适用于Struts1,Servlet,JSP环境。
     * 
     * 下面的情况标识校验通过:
     * 1)请求中包含名字为TokenConstants.TOKEN_PARAMETER_NAME所指定的参数。
     * 2)会话中包含名字为TokenConstants.TOKEN_KEY_NAME所指定的属性。
     * 3)1参数的值和2属性的值(字符串类型)相等(忽略大小写)。
     * 
     * @param request HTTP请求对象。
     * @return 验证通过返回true,否则返回false。
     */
    public static boolean isTokenValid(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            return false;
        }

        boolean isLegal = true;
        String[] tokenParams = (String[]) request.getParameterValues(TOKEN_PARAMETER_NAME);
        if (tokenParams == null) {
            isLegal = false;
        } else {
            String token = tokenParams[0];
            if (token == null) {
                isLegal = false;
            } else {
                String sessionToken = (String) session.getAttribute(TOKEN_KEY_NAME);
                if (!token.equalsIgnoreCase(sessionToken)) {
                    isLegal = false;
                }
            }
        }
        //删除会话中的token信息
        session.removeAttribute(TOKEN_KEY_NAME);

        return isLegal;
    }

    /**
     * 向客户端生成验证码图片。
     * 
     * @param response HHTP 响应对象。
     * @param session 包含会话属性信息的Map对象。
     * @param width 验证码图片的宽度。
     * @param height 验证码图片的高度。
     * @throws IOException 执行操作时发生网络错误时。
     */
    public static void generateTokenImage(HttpServletResponse response, HttpSession session, int width, int height) throws IOException {
        //设置响应内容为图片格式
        response.setContentType("image/jpeg");

        //禁止浏览器缓存
        response.addHeader("pragma", "NO-cache");
		response.addHeader("Cache-Control", "no-cache");
		response.addDateHeader("Expries", 0);

        //绘制图片
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();

        //以下填充背景颜色
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);

        //设置字体颜色
        g.setColor(Color.RED);
        Font font = new Font("Arial", Font.BOLD, 18);
        g.setFont(font);

        //绘制
        String token = (String) session.getAttribute(TOKEN_KEY_NAME);
        g.drawString(token, 5, height - 2);
        g.dispose();

        //发送内容到客户端
        ServletOutputStream out = response.getOutputStream();
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
        encoder.encode(image);
        out.close();
    }
}
 

 

 

0
0
分享到:
评论

相关推荐

    仿支付宝滑块验证码前端实现

    本实例将详细探讨如何在前端实现仿支付宝风格的滑块验证码功能。 首先,我们需要理解滑块验证码的基本工作原理。它通常包括两部分:一个固定的背景图像,上面有一个可移动的滑块。用户需要通过拖动滑块,使得滑块...

    计算机菜鸟学飞文章集锦

    计算机菜鸟学飞文章是专门为研究系统、电脑故障、计算机技巧等的菜鸟搜集的文章。

    选图验证码(附带源码).zip

    在这个描述中,作者可能用PB9来实现了图片验证码的后端逻辑,包括生成随机图像、存储验证码信息以及与前端交互等功能。 【标签】"pb9 图片验证码" 明确了讨论的主题,即使用PowerBuilder 9来设计和实现图片验证码。...

    c# 验证码识别源代码

    只要你有一定的c#编程基础,只要半天时间仔细阅读这份代码,你就可以从完全不懂验证码识别的菜鸟变成一个能破解一些傻瓜验证码的高手。 希望尊重他人劳动成果,不要上传此代码到别的地方。谢谢!

    验证码普通识别源码-PHP

    验证码识别在IT领域中是一个重要的子话题,尤其是在网络安全和自动化测试中。PHP作为一种流行的服务器端...通过分析和实践提供的源码,我们可以深入了解验证码识别的实现过程,并可能为自己的项目提供有价值的参考。

    菜鸟飞飞飞-微服务架构的想法

    菜鸟飞飞飞-微服务架构的想法

    久游菜鸟私服编辑工具

    它特别适合对游戏开发感兴趣但缺乏专业编程知识的“菜鸟”玩家,他们可以通过这个工具,实现自己的游戏创意,享受到制作和分享游戏内容的乐趣。 至于【压缩包子文件的文件名称列表】中的“菜鸟编辑器”,这很可能是...

    菜鸟学易模块 常用功能等

    《菜鸟学易模块:探索常用功能与编程基础》 易语言是一种面向中文用户的编程语言,旨在降低编程的门槛,让更多的初学者能够快速上手。本压缩包“菜鸟学易模块”聚焦于新手在学习易语言过程中可能会用到的一些常见...

    验证码的一个小实例

    在这个名为“验证码的小实例”中,我们将探讨验证码的基本原理、类型以及实现一个简单验证码的步骤。 验证码的核心在于它的随机性和可验证性。当用户在网页上看到一个验证码时,他们需要正确识别并输入显示的图像或...

    jsp页面最简单的验证码

    - **JavaScript交互**:使用JavaScript实现了验证码图片的刷新功能和表单验证逻辑。 - **`test()` 函数**:用于刷新验证码图片,点击图片时触发该函数,更新图片的`src`属性,调用后端生成验证码的接口。 - **`...

    验证码高级识别源码-PHP

    验证码高级识别源码-PHP是基于PHP编程语言实现的一种用于图像验证码识别的技术。在网络安全领域,验证码被广泛用于防止自动化的机器人程序进行恶意操作,如批量注册、恶意投票等。这个源码提供了一种方法来识别这些...

    最新DR5加强版菜鸟版.rar

    智能液化功能让调整照片中的形体变得轻而易举,无论是需要瘦身还是调整脸型,都能通过这一工具实现,而且操作简单,效果自然,极大地提升了图像编辑的灵活性和创造性。 色彩和美妆调整是提升照片美感的重要步骤。DR...

    菜鸟操作WINDOWS大全 工具

    菜鸟操作WINDOWS大全菜鸟操作WINDOWS大全菜鸟操作WINDOWS大全菜鸟操作WINDOWS大全菜鸟操作WINDOWS大全菜鸟操作WINDOWS大全菜鸟操作WINDOWS大全菜鸟操作WINDOWS大全菜鸟操作WINDOWS大全菜鸟操作WINDOWS大全菜鸟操作...

    菜鸟浏览器

    在实现这一功能的背后,涉及到多个IT知识点: 1. **网络爬虫技术**:"菜鸟浏览器"的核心部分很可能是基于网络爬虫技术,通过模拟用户行为,自动抓取并分析网页内容。爬虫程序会遍历QQ空间的相关页面,寻找与背景...

    菜鸟窝 菜鸟商城 菜鸟新闻全套

    # 菜鸟商城 # 是一个仿淘宝客户端的实战课程,功能包括:1.支付(支付宝,微信,百度钱包) 、首页 、热卖 、商品大全 、购物车 、我的 、商品列表 、商品详情 、注册/登录 、收货地址 、我的订单 、我的收藏 ..... ...

    菜鸟窝企业项目课程《菜鸟商城》的源码.rar

    《菜鸟商城》是一款基于Java和安卓技术的企业级电商项目,旨在提供一个全面的在线购物平台。这个项目不仅包含了后台管理系统,还涵盖了移动端的安卓应用,为用户和商家提供了丰富的功能。下面将详细介绍该项目中的...

    Python 菜鸟也可以实现的“背单词”程序 Python源码

    Python 菜鸟也可以实现的“背单词”程序 Python源码Python 菜鸟也可以实现的“背单词”程序 Python源码Python 菜鸟也可以实现的“背单词”程序 Python源码Python 菜鸟也可以实现的“背单词”程序 Python源码Python ...

    2022菜鸟驿站“全域明星”产品手册-菜鸟驿站五大核心媒介.pdf

    2022菜鸟驿站“全域明星”产品手册-菜鸟驿站五大核心媒介 “全域明星”产品手册是菜鸟驿站推出的五大核心媒介之一,旨在提供一种高效、低成本、精准的广告解决方案。该产品手册主要介绍了菜鸟驿站的五大核心媒介,...

    菜鸟驿站包裹管理系统.zip

    《菜鸟驿站包裹管理系统——C语言实现详解》 在信息技术飞速发展的今天,各种管理系统已经成为企业和组织提高效率的重要工具。在本案例中,我们将探讨一款基于C语言编程的“菜鸟驿站包裹管理系统”,它主要用于帮助...

    菜鸟数据中台技术演进之路.pdf

    菜鸟数据中台是阿里巴巴集团旗下的数据中台平台,旨在提供数据运营、数据服务和数据管理等功能,帮助企业实现数字化转型和数据驱动的业务增长。以下是菜鸟数据中台技术演进之路的详细知识点: 一、数据中台概述 ...

Global site tag (gtag.js) - Google Analytics