Web用户登录---验证码的设计与实现

在开发中验证码是比较常用到有效防止这种问题对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试的方式。

验证码生成步骤:
1、获得随机生成的颜色,画出随机线条生成背景底。
2、String codes = "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYXZ";随机选取4个字符构成验证码。随机字符集合中不包括0和o,O,1和l,因为这些不易区分。
3、选取4个字符进行旋转、伸缩后再单个单个绘制;生成4字符验证码。

示例源码:login.jsp---登录表单。

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<html>
<head>
<title>登录页面</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
 
<script type="text/javascript">
  function myReload() {
    document.getElementById("CreateCheckCode").src = 
        document.getElementById("CreateCheckCode").src+ "?nocache=" + new Date().getTime();
  }
</script>
 
</head>
 
<body>
  <form action="loginServlet" method="get">
      <p class="font tdheight">
        验证码:<input type="text" name="checkCode" style="width:80px;height:35px;"> 
        <img src="pictureCheckCode" id="CreateCheckCode" align="middle" style="margin-top:-10px;"> <br> 
        
        <a href="" onclick="myReload()" style="font-size:12px;color:red;margin-left:156px;">看不清,换一个</a>
      </p>
      <br><input type="submit" value="提交"
            class="font" style="width:240px;height:35px;background:#f19e28">
 
    </form>
</body>
</html>

LoginServlet---处理登录请求。

import java.io.IOException;
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 javax.servlet.http.HttpSession;
 
/**
 *处理登录请求
 */
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        request.setCharacterEncoding("UTF-8"); 
        response.setCharacterEncoding("UTF-8");
        
        String code = request.getParameter("checkCode");
        HttpSession session = request.getSession();
        if (!code.equalsIgnoreCase((String) session.getAttribute("randCheckCode"))) {
            request.setAttribute("errormsg", "验证码不正确");
            response.getWriter().println("<script> type='text/javascript'>window.alert('*验证码错误!');window.location.href='login.jsp'</script>");
        }
        response.getWriter().println("<script> type='text/javascript'>window.alert('*用户登录成功!');window.location.href='login.jsp'</script>");
    }
 
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

PictureCheckCode---验证码生成与更新。

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
 
import javax.imageio.ImageIO;
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 javax.servlet.http.HttpSession;
 
/**
 *验证码生成与更新
 */
@WebServlet("/pictureCheckCode")
public class PictureCheckCode extends HttpServlet {
 
    private static final long serialVersionUID = 1L;
    
 
    /* 该方法主要作用是获得随机生成的颜色 */
    public Color getRandColor(int s, int e) {
        Random random = new Random();
        if (s > 255)
            s = 255;
        if (e > 255)
            e = 255;
        int r, g, b;
        r = s + random.nextInt(e - s); // 随机生成RGB颜色中的r值
        g = s + random.nextInt(e - s); // 随机生成RGB颜色中的g值
        b = s + random.nextInt(e - s); // 随机生成RGB颜色中的b值
        return new Color(r, g, b);
    }
    
    private Random r = new Random();
    
    // 随机字符集合中不包括0和o,O,1和l,因为这些不易区分 
    private String codes = "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYXZ";  
    private char randomChar() {  
        int index = r.nextInt(codes.length());  
        return codes.charAt(index);  
    } 
 
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
 
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        
        // 设置不缓存图片
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "No-cache");
        response.setDateHeader("Expires", 0);
        
        // 指定生成的响应图片,一定不能缺少这句话,否则错误.
        response.setContentType("image/jpeg");
        int width = 80, height = 35; // 指定生成验证码的宽度和高度
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // 创建BufferedImage对象,其作用相当于一图片
        Graphics g = image.getGraphics(); // 创建Graphics对象,其作用相当于画笔
        Graphics2D g2d = (Graphics2D) g; // 创建Grapchics2D对象
        
        Random random = new Random();
        Font mfont = new Font("楷体", Font.BOLD, 16); // 定义字体样式
        g.setColor(getRandColor(200, 250));
        g.fillRect(0, 0, width, height); // 绘制背景
        g.setFont(mfont); // 设置字体
        g.setColor(getRandColor(180, 200));
 
        // 绘制100条颜色和位置全部为随机产生的线条,该线条为2f
        for (int i = 0; i < 100; i++) {
            int x = random.nextInt(width - 1);
            int y = random.nextInt(height - 1);
            int x1 = random.nextInt(6) + 1;
            int y1 = random.nextInt(12) + 1;
            BasicStroke bs = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); // 定制线条样式
            Line2D line = new Line2D.Double(x, y, x + x1, y + y1);
            g2d.setStroke(bs);
            g2d.draw(line); // 绘制直线
        }
        
        
        //用来保存验证码字符串文本内容  
        StringBuilder sb = new StringBuilder();  
        
        for (int i = 0; i < 4; ++i) {// 随机生成4个字符  
            String sTemp = String.valueOf(randomChar());
            sb.append(sTemp);  
            
            Color color = new Color(20 + random.nextInt(110), 20 + random.nextInt(110), random.nextInt(110));
            g.setColor(color);
            // 将生成的随机数进行随机缩放并旋转制定角度 PS.建议不要对文字进行缩放与旋转,因为这样图片可能不正常显示
            
            /* 将文字旋转制定角度 */
            Graphics2D g2d_word = (Graphics2D) g;
            AffineTransform trans = new AffineTransform();
            trans.rotate((45) * 3.14 / 180, 15 * i + 8, 7);
            
            /* 缩放文字 */
            float scaleSize = random.nextFloat() + 0.8f;
            if (scaleSize > 1f)
                scaleSize = 1f;
            trans.scale(scaleSize, scaleSize);
            g2d_word.setTransform(trans);
            g.drawString(sTemp, 15 * i + 18, 14);
        }
        
        HttpSession session = request.getSession(true);
        session.setAttribute("randCheckCode", sb.toString());
        System.out.println("sRand="+sb.toString());
        g.dispose(); // 释放g所占用的系统资源
        ImageIO.write(image, "JPEG", response.getOutputStream()); // 输出图片
    }
 
}

测试:

原文:https://blog.csdn.net/ljheee/article/details/72799746

猜你喜欢

转载自www.cnblogs.com/hooly/p/9501175.html