【java图片验证码】Java 服务端生成图片验证码及验证

【java图片验证码】Java 服务端生成图片验证码及验证目录 简介 分析 代码实现 测试与运行 简介 验证码是防止有人利用机器人自动批量注册 对特定的注册用户用特定程序暴力激活成功教程方 式进行不断的登录 灌水 因为验证码是一个混合了数字或符号的图片 人眼看起来都费劲 机器识别起来就更困难 分析

大家好,我是讯享网,很高兴认识大家。

目录

简介

分析

代码实现:

测试与运行


简介

验证码是防止有人利用机器人自动批量注册、对特定的注册用户用特定程序暴力激活成功教程方 式进行不断的登录、灌水。因为验证码是一个混合了数字或符号的图片,人眼看起来都费劲, 机器识别起来就更困难。

分析

登录表单很可能遭到模拟登录的暴力激活成功教程攻击,要么轻易获得特定账户的登录信息,要么给服务器增加了大量的负荷。解决的办法,一般就是在登录前给出一个随机的信息(验证码),非法的非 Web 途径登录者会看不到这个验证码,从而让用户安全登录。为防止攻击者破获验证码,需将验证信息作为图像显示在 Web 上。

代码实现:

利用 Servlet 实现一个 4 位的彩色验证码数据。

 import java.io.*;  import java.awt.*;  import java.awt.image.*;  import java.util.*;  import javax.imageio.*;  import javax.servlet.ServletException;  import javax.servlet.ServletOutputStream;  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("/Image")  public class Image extends HttpServlet {  ​      protected void processRequest(HttpServletRequest request, HttpServletResponse response)              throws ServletException, IOException {          response.setContentType("image/jpeg");          //禁止图像缓存          response.setHeader("Pragma","No-cache");          response.setHeader("Cache-Control","no-cache");          response.setDateHeader("Expires", 0);          HttpSession session=request.getSession();          // 在内存中创建图象          int width=100, height=40;          BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);          // 获取图形上下文          Graphics g = image.getGraphics();          //生成随机类          Random random = new Random();          // 设定背景色          g.setColor(getRandColor(200,250));          g.fillRect(0, 0, width, height);          //设定字体          g.setFont(new Font("Times New Roman",Font.PLAIN,28));                  // 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到          g.setColor(getRandColor(160,200));          for (int i=0;i<155;i++) {              int x = random.nextInt(width);              int y = random.nextInt(height);              int xl = random.nextInt(12);              int yl = random.nextInt(12);              g.drawLine(x,y,x+xl,y+yl);         }          // 取随机产生的认证码(4位数字)          String sRand="";          //准备一个数字加字母字典          String string = "abcdefghijklmnopqrstuvwxyz";          for (int i=0;i<4;i++){              char rand=string.charAt(random.nextInt(string.length()));              sRand+=rand;              // 将认证码显示到图象中              //调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成              g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));              g.drawString(Character.toString(rand),13*i+25,30);         }          // 将认证码存入SESSION          session.setAttribute("rand",sRand);          // 图象生效          g.dispose();          ServletOutputStream responseOutputStream =response.getOutputStream();          // 输出图象到页面          ImageIO.write(image, "JPEG", responseOutputStream);          //以下关闭输入流!          responseOutputStream.flush();          responseOutputStream.close();     }  ​      //给定范围获得随机颜色      Color getRandColor(int fc,int bc){          Random random = new Random();          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);     }  ​      protected void doGet(HttpServletRequest request, HttpServletResponse response)              throws ServletException, IOException {          processRequest(request, response);     }  ​      protected void doPost(HttpServletRequest request, HttpServletResponse response)              throws ServletException, IOException {          processRequest(request, response);     }  }

讯享网

写完后保存文件,启动服务器,访问 Servlet 后可以看到页面中生成了一张图片验证码


讯享网

测试与运行

该 Servlet 仅仅是一个验证码图像,接下来我们用 jsp 编写一个包含该验证码的登录页面

jsp 程序代码如下:

讯享网 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 <%
     String path = request.getContextPath();
     String basePath = request.getScheme() + "://" + request.getServerName() + ":" +request.getServerPort() + path;
 %>
 ​
 <!DOCTYPE HTML>
 <html>
 <head>
     <title>表单验证</title>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
     <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
     <META HTTP-EQUIV="Expires" CONTENT="0">
     <style>
         div {
             width: 240px;
             height: 100%;
             margin: 30px auto;
         }
 ​
         label {
             margin: 5px auto;
             height: 22px;
             line-height: 22px;
             float: left;
         }
 ​
         .input {
             margin: 5px auto;
             height: 20px;
             float: right;
         }
 ​
         #submit {
             width: 100px;
             height: 35px;
             margin: 5px 8px;
         }
     </style>
 </head>
 ​
 <body>
 <div>
     <form id="myForm" action="" method="post" autocomplete="off" >
         <label>用户名:</label><input class="input" type="text" name="name" placeholder="请输入用户名"><br>
         <label>密码:</label><input class="input" type="password" name="password" placeholder="请输入密码"><br>
         <div style="margin-top: 10px;">
             <div style="height: 10px;width: 200px;margin-bottom: 0px"> </div>
             <input style="width: 110px;height: 33px;margin-right: 20px;float: left " type="text" placeholder="图片验证码" name="code">
             <img style="float: right" title="看不清?点击切换。" id="changeServletImg" src="<%=basePath%>/Image/Image">
         </div>
         <input style="margin-left: 140px" id="submit" type="button" value="登录">
     </form>
     <div id="errorTips" style="text-align: center;font-size: 18px;color: red"></div>
 </div>
 </body>
 <script>
     window.onload = function () {
 ​
         var changeServletImgDOM = document.getElementById('changeServletImg');
         //点击图片时改变验证码
         changeServletImgDOM.onclick=change;
 ​
         function change() {
             changeServletImgDOM.src="<%=basePath%>/Image/Image?"+new Date().getTime();
         };
 ​
         document.getElementById('submit').onclick = check;
 ​
         function check () {
 ​
             //获取表单数据
             var name = document.getElementsByName('name')[0].value;
             var password = document.getElementsByName('password')[0].value;
             var code = document.getElementsByName('code')[0].value;
             var formInfo = 'name=' + name + '&password=' + password + '&code=' + code;
             var xhr = new XMLHttpRequest();
             //设置请求参数
             xhr.open("post","Example_13",true);
             xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=utf-8");
             //发送请求
             xhr.send(formInfo);
             // 设置响应 HTTP 请求状态变化的函数
             xhr.onreadystatechange = function() {
                 if (xhr.status == 200 && xhr.readyState == 4) {
                     if(xhr.responseText == 'OK') {
                         // 验证成功时跳转页面
                         location.href = 'loginSuccess.html';
                     } else {
                         // 验证失败时给出错误提示
                         document.getElementById('errorTips').innerText = xhr.responseText;
                     }
                 }
             }
         }
     }
 </script>
 </html>

loginSuccess.html 代码如下:

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>欢迎</title>
 </head>
 <body>
 <h1>登录成功!</h1>
 </body>
 </html>

由于 jsp 先于 java 执行,导致 jsp 页面图片验证码获取的session值始终是示前一个。

所以无法直接在填写表单的页面完成验证码的验证。

接下来编写一个 Servlet 来接收由 AJAX 发送的表单数据,然后通过 AJAX 完成错误信息的回显,以及页面跳转。

(为了方便,这里用 equals 进行验证,不连接数据库) 【用户名和密码为 admin】

servlet 程序代码如下:

讯享网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;
 import java.io.IOException;
 import java.io.PrintWriter;
 ​
 @WebServlet("/Example_13")
 public class Example_13 extends HttpServlet {
     
     //判断用户是否存在 (为了方便,这里用 equals 进行验证,不连接数据库)
     public boolean isAdmin(String name,String password){
         //假设用户不存在
         boolean isExist = false;
         if("admin".equals(name) && "admin".equals(password)) {
             isExist = true;
         }
         return isExist;
     }
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
         doPost(req, resp);
     }
 ​
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
         req.setCharacterEncoding("utf-8");
         resp.setContentType("text/html;charset=utf-8");
         PrintWriter out = resp.getWriter();
         //获取表单数据
         String name = req.getParameter("name");
         String password = req.getParameter("password");
         String code = req.getParameter("code");
 ​
         //获取图片验证码
         HttpSession session =  req.getSession();
         String rand = (String)session.getAttribute("rand");
         //验证图片验证码
         if(rand.equals(code)) {
             getConnect();
             //验证用户名 密码
             if(isAdmin(name,password)) {
                 closeConnect();
                 out.print("OK");
             } else {
                 out.print("用户名或密码错误!");
             }
         } else {
             out.print("验证码错误,验证失败!");
         }
     }
 }

效果如下:

小讯
上一篇 2025-04-06 20:32
下一篇 2025-02-07 14:41

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/47796.html