整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          前端設計- JavaScript驗證碼制作及實例分析

          網頁設計中,尤其表單填寫提交過程中,為防止機器自動登錄,很多網頁都采用驗證碼技術,允許用戶輸入而盡量避免自動登錄。驗證碼實現的方法有很多,PHP繪圖技術可以在服務端生成驗證碼并發送客戶端,HTML5技術下可以使用canvas與JS腳本實現在客戶端瀏覽器自動生成驗證碼。本文給出JS+Canvas驗證碼的解決措施,所制作驗證碼實現效果如下圖所示:

          驗證碼實現效果動態圖


          實現原理

          本例驗證碼的實現主要包括驗證碼字符串的生成、背景干擾點實現及干擾直線的生成三部分。最終通過canvas繪圖技術將生成的驗證碼字符串、背景及干擾直線顯示到畫布上。主要涉及技術或知識點包括canvas繪圖技術、數組、鼠標點擊事件、隨機函數等。以下從驗證字符串、背景干擾點及干擾直線三方面對實現過程進行說明。

          驗證字符串

          驗證字符串部分主要借助數組存儲驗證碼所有字符,通過調用Math對象的隨機函數獲取數組下標,并通過數組下表讀取數組元素,將讀取的數組元素組裝成完整字符串。其實現核心代碼如下:

          驗證字符串獲取核心代碼

          如上圖所示,本例驗證碼字符包括數字與大寫字母,getCode函數返回值即為4位驗證碼字符串。

          背景干擾點

          背景干擾點可以直接使用canvas對應的繪圖方法進行繪制,本例為簡化開發過程,降低難度直接使用drawImage繪圖方式加載背景圖片,實現干擾點效果。背景圖片如下:

          背景干擾點圖片

          通過調用drawImage方法,指定截取的坐標位置參數,可實現背景干擾點的動態變化效果,背景干擾點實現核心代碼如下:

          背景干擾點實現代碼

          其中getXsize與getYsize為獲取繪圖截取背景圖片的坐標位置,通過使用隨機函數實現從背景圖片不同位置截取進行繪圖輸出。

          干擾直線

          干擾直線實現較為簡單,直接通過JS提供的moveTo與lineTo方法完成直線的繪制,本例繪制了兩條直線,一條為黑色干擾線,一條為白色干擾線。在繪制過程兩端點需要使用Math隨機函數生成符合條件隨機坐標。干擾直線相關實現代碼如下:

          干擾直線實現核心代碼

          干擾直線實現核心代碼如上圖,其中getLsize方法主要用于獲取隨機端點Y軸坐標值。strokeStyle主要用于設置繪圖直線的顏色。

          驗證碼顯示輸出

          驗證碼的顯示輸出主要使用fillText()方法在canvas指定位置進行文字輸出,本例使用第三方ttf字體,因此在HTML頁面中對字體進行了加載。驗證碼顯示輸出實現代碼如下:

          驗證碼繪制

          驗證碼顯示輸出核心代碼如上圖所示,其中myfont為加載的第三方字體。

          繪圖基礎部分

          繪圖基礎部分主要包括前端canvas元素的布局等。包括屬性的設置,js部分元素的獲取及屬性設置等。

          其他工作

          我們一般接觸的驗證碼,都可以點擊圖片實現驗證碼的刷新,因此本例為canvas標記添加了onclick事件,將所有驗證碼生成的代碼封裝到showCode()函數中,通過調用showCode函數實現驗證碼的刷新。本例完整JS腳本部分代碼如下:

          JS實現腳本代碼


          本頭條號長期關注編程資訊分享;編程課程、素材、代碼分享及編程培訓。如果您對以上方面有興趣或代碼錯誤、建議與意見,可以聯系作者,共同探討。期待大家關注!如需案例完整代碼請關注并私信,往期前端設計文章鏈接如下:

          1. 前端設計-Ajax技術及實例展示
          2. 前端設計-響應式頁面開發基礎
          3. Web開發前端、后端與全棧的區別是什么?

          網頁頁面的使用中為防止“非人類”的大量操作和防止一些的信息冗余,增加驗證碼校驗是許多網站常用的方式。

          而讓用戶輸入字母和數字組合的驗證碼是最經典也是最常用的方式。
          這一篇是純利用現有JDK提供的繪圖類(ImageIO)類制作,這個過程比較復雜且需要了解ImageIO類。

          今天發布的第二篇文章是利用Hutool工具類來實現的,該工具類已經封裝驗證碼所需的相關類等,使用起來較為簡單和方便。

          驗證碼的生成和校驗過程均使用Servlet和JSP的結合來實現,Servlet的相關內容可以參閱

          Servlet技術:https://mp.weixin.qq.com/s/__e_ef0SI6kVPiRaU0MXJw

          如何利用基礎的JSP知識來實現網頁的驗證碼校驗呢?

          驗證碼校驗分析

          首先要驗證碼的校驗的過程。

          驗證碼校驗分為三部分:

          1. 生成驗證碼
          2. 獲取用戶輸入的驗證碼
          3. 判斷驗證碼是否輸入正確

          驗證碼的生成實際就是輸出一個圖像,所以在這里使用ImageIO來生成圖片,然后結合使用隨機數(Random)來實現隨機生成驗證上的內容,最后進而展示出來,然后利用Session對象存儲驗證碼的內容。在用戶輸入驗證碼的時候可以用request來獲取用戶輸入的內容,讓其余Session對象中保存的驗證碼內容進行比較,若一致則驗證成功,不一致就驗證失敗。

          生成驗證碼

          先創建一個圖片的緩沖區:

          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="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
          

          創建隨機的驗證碼內容:

          Random r=new Random();
                   int len=ch.length;
                   int index; //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]);
                   }
          

          將驗證碼的內容存入Session及顯示在頁面上:

           request.getSession().setAttribute("piccode",sb.toString()); 
           ImageIO.write(bi, "JPG", response.getOutputStream()); 
          

          完整代碼:

          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 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();//轉化為字符型的數組
                  Random r = new Random();
                  int len = ch.length;
                  int index; //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());
              }
          }
          

          測試驗證碼

          在測試之前需要先在web.xml文件中配置一下:

          <servlet>
                  <servlet-name>ImageServlet</servlet-name>
                  <servlet-class>com.kailong.servlet.ImageServlet</servlet-class>
              </servlet>
          
              <servlet-mapping>
                  <servlet-name>ImageServlet</servlet-name>
                  <url-pattern>/imageServlet</url-pattern>
              </servlet-mapping>
          

          啟動服務器后在瀏覽器中輸入http://localhost:8080/工程名/imageServlet 即可

          驗證碼的生成已經實現成功,下面實現驗證驗證碼的Servlet。

          校驗驗證碼

          先新建一個jsp用戶界面:

          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
              <title>登錄界面</title>
          </head>
          <body>
          <form action="<%= request.getContextPath()%>/loginServlet" method="get" >
              驗證碼:<input  type="text" name="checkCode"/><br/>
              <img alt="驗證碼" id="imagecode" src="<%= request.getContextPath()%>/imageServlet"/>
              <input type="submit" value="提交">
          </form>
          </body>
          </html>
          

          校驗驗證碼過程:

          1. 將生成的驗證碼內容保存在Session對象中
          2. 獲取用戶輸入的驗證碼內容
          3. 將兩個內容進行對照

          代碼實現:

          獲取Session中的驗證碼內容:

          String piccode=(String) request.getSession().getAttribute("piccode");
          

          獲取用戶輸入的驗證碼內容:

          String checkCode=request.getParameter("checkCode"); 
          

          驗證碼判斷(使用了PrintWriter將相關內容輸出)

          response.setContentType("text/html;charset=utf-8");//解決亂碼問題
          PrintWriter out=response.getWriter();
          if(checkCode.equals(piccode))
          {
              out.println("驗證碼輸入正確!");
          }
          else
          {
              out.println("驗證碼輸入錯誤!!!");
          }
          out.flush();//將流刷新
          out.close();//將流關閉
          

          完整代碼:

          public class LoginServlet extends HttpServlet {
              public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
              //用于驗證驗證碼
              {
                  String piccode = (String) request.getSession().getAttribute("piccode");
                  String checkCode = request.getParameter("checkCode");
                  response.setContentType("text/html;charset=utf-8");//解決亂碼問題
                  PrintWriter out = response.getWriter();
                  if (checkCode.equals(piccode)) {
                      out.println("驗證碼輸入正確!");
                  } else {
                      out.println("驗證碼輸入錯誤!!!");
                  }
                  out.flush();//將流刷新
                  out.close();//將流關閉
              }
          }
          

          測試驗證碼校驗

          測試前先在web.xml文件中配置一下:

           <servlet>
                  <servlet-name>LoginServlet</servlet-name>
                  <servlet-class>com.kailong.servlet.LoginServlet</servlet-class>
              </servlet>
              <servlet-mapping>
                  <servlet-name>LoginServlet</servlet-name>
                  <url-pattern>/loginServlet</url-pattern>
              </servlet-mapping>
          

          添加驗證碼刷新

          在驗證碼生成之后,用戶在識別的時候可能不能正確識別,這時候就需要刷新一下重新生成。

          添加超鏈接實現刷新:

          login.jsp:

          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
              <title>登錄界面</title>
              <script>
                  function reloadCode() {
                    var time=new Date().getTime();
                    document.getElementById("imagecode").src="<%= request.getContextPath()%>/imageGenerate?d="+time;
                  }
              </script>
          </head>
          <body>
          <form action="<%= request.getContextPath()%>/loginServlet" method="get" >
              驗證碼:<input  type="text" name="checkCode"/><br/>
              <img alt="驗證碼" id="imagecode" src="<%= request.getContextPath()%>/imageServlet"/>
              <a href="javascript:reloadCode();">看不清楚</a><br>
              <br/><input type="submit" value="提交">
          </form>
          </body>
          </html>
          

          js部分的Date相關是防止瀏覽器緩存后不能正常刷新,添加時間的唯一性來實現能夠及時刷新和展示。

          js 部分可以參閱:JavaScript 語言入門: https://mp.weixin.qq.com/s/37CaC25_1agb-aXBLhUKtg

          也可以在ImageServlet中添加防止瀏覽器緩存的語句:

          response.setHeader("Pragma", "No-cache");
          

          公眾號本文地址:https://mp.weixin.qq.com/s/XHucabQ_WwUx2OMDGSTMkw

          歡迎關注公眾號:愚生淺末。


          近有小伙伴提問:能否說下web驗證的原理,感覺文字描述不清楚,于是就用代碼簡單的演示下:此代碼是需要依賴:

          sanic==19.9.0Pillow==7.0.0
          

          import random
          import string
          import uuid
          import base64
          import platform
          from PIL import Image, ImageDraw,ImageFont
          from io import BytesIO
          from sanic import Sanic
          from sanic.response import HTTPResponse,text
          from sanic.views import HTTPMethodView
          
          
          app = Sanic()
          
          session = {}
          
          
          class VerifyCode:
              def __init__(self, numbers:int):
                  """
                  指定:生成的數量
                  """
                  self.number = numbers
          
              def draw_lines(self, draw, num, width, height):
                  """劃線"""
          
                  x1 = random.randint(0, width / 2)
                  y1 = random.randint(0, height / 2)
                  x2 = random.randint(0, width)
                  y2 = random.randint(height / 2, height)
                  draw.line(((x1, y1), (x2, y2)), fill='black', width=1)
          
              def random_color(self):
                  """隨機顏色"""
                  return (random.randint(32, 127), random.randint(32, 127), random.randint(32, 127))
          
              def gene_text(self):
                  """生成驗證碼"""
                  return "".join(random.sample(string.ascii_letters+string.digits, self.number))
          
              def get_verify_code(self):
                  """
                  draw.text():
                      文字的繪制,第一個參數指定繪制的起始點(文本的左上角所在位置),第二個參數指定文本內容,第三個參數指定文本的顏色,第四個參數指定字體(通過ImageFont類來定義)
                  """
                  code = self.gene_text()
                  width, height = 130, 30
                  im = Image.new("RGB", (width, height), "white")
                  # 這里指定字體的路徑
                  sysstr = platform.system()
                  font = None
                  if sysstr == "Windows":
                      font = ImageFont.truetype("C:\WINDOWS\Fonts\STXINGKA.TTF", 25)
                  elif sysstr == "Darwin":
                      font = ImageFont.truetype('/Library/Fonts/AppleMyungjo.ttf', 25)
                  draw = ImageDraw.Draw(im)
                  for item in range(self.number):
                      draw.text((5+random.randint(-5,5)+23*item, 5+random.randint(-5, 5)), text=code[item],
                                fill=self.random_color(), font=font)
                      self.draw_lines(draw, self.number, width, height)
                  return im, code
          
          
          class SimpleView(HTTPMethodView):
              body = """
                  <html>
                      <head>
                          <meta charset="UTF-8">
                              <title>登錄</title>
                              <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
                              <!-- 可選的 Bootstrap 主題文件(一般不用引入) -->
                              <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
                              <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
                              <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
                      </head>
                      <body>
                          <form class="form-inline" method="post" action="/code">
                              <div>
                                  <div class="form-group">
                                      {error}                               
                                    </div>
                                  <div class="form-group">
                                          <label for="exampleInputName2">驗證碼</label>
                                          <input type="text" class="form-control" id="captcha" name="code">
                                  </div>
                                  
                                  <div class="form-group">
                                      <img src="data:image/jpeg;base64,{base64_data}" class="img-img-rounded">
                                  </div>
                                  <div>
                                      <button type="submit">驗證</button>
                                  </div>
                              </div>
                          </form>
                      </body>
                  </html>
                  """
          
              async def get(self, request):
                  return self.response(error="")
          
              async def post(self, request):
                  uuid = request.cookies.get("uuid", "1")
                  verfy_code = request.form.get("code", "2").lower()
                  code = session.get(uuid, "").lower()
                  if code == verfy_code:
                      return text('驗證碼正確')
                  return self.response(error='<input class="form-control" id="disabledInput" type="text" placeholder="驗證碼錯誤" disabled>')
          
              def response(self, error):
                  im, code = VerifyCode(5).get_verify_code()
                  buf = BytesIO()
                  im.save(buf, "jpeg")
                  buf_str = buf.getvalue()
                  base64_data = base64.b64encode(buf_str).decode()
                  id = uuid.uuid1().__str__()
                  session[id] = code
                  body = self.body.format(base64_data=base64_data, error=error)
                  response = HTTPResponse(body, content_type="text/html; charset=utf-8")
                  response.cookies["uuid"] = id
                  return response
          
          
          app.add_route(SimpleView.as_view(), '/code')
          
          if __name__ == "__main__":
              app.run(host="0.0.0.0", port=8000)
          

          只是簡單的實現了驗證碼,沒有實現點擊刷新,點擊刷新的原理不難:異步請求+刷新接口就好了,記得更新對應的session的key里面的value

          0人點贊

          隨筆


          主站蜘蛛池模板: 偷拍精品视频一区二区三区| 久久国产香蕉一区精品| 人妻少妇精品一区二区三区| 精品一区二区高清在线观看| 中文字幕日韩一区二区不卡| 亚洲Av永久无码精品一区二区| 久久伊人精品一区二区三区| 亚洲国产激情在线一区| 国产精品久久一区二区三区 | 日韩精品一区二区三区国语自制 | 狠狠色成人一区二区三区| 精品午夜福利无人区乱码一区| 中文字幕一区二区三区精彩视频| 精品一区二区三区在线观看视频 | 国产av一区最新精品| 正在播放国产一区| 国产aⅴ精品一区二区三区久久 | 日韩精品一区二区三区老鸭窝| 久久久久无码国产精品一区| 国产一区二区四区在线观看| 国产成人精品视频一区二区不卡 | 日韩精品久久一区二区三区| 精品无码中出一区二区| 久久久久人妻一区精品| 78成人精品电影在线播放日韩精品电影一区亚洲 | 99久久无码一区人妻a黑| 无码一区二区三区亚洲人妻| 国产一区三区二区中文在线 | 69福利视频一区二区| 欧美激情一区二区三区成人| 一区二区三区在线播放| 亚洲AV本道一区二区三区四区| 亚洲高清毛片一区二区| 久久精品一区二区三区中文字幕| 在线观看亚洲一区二区| 一区二区三区在线观看免费| 日韩一区二区视频在线观看| 制服中文字幕一区二区| 狠狠综合久久av一区二区| 亚洲美女视频一区| 无码日韩精品一区二区人妻|