selenium+java破解极验滑动验证码的示例代码

摘要

分析验证码素材图片混淆原理,并采用selenium模拟人拖动滑块过程,进而破解验证码。

人工验证的过程

1、打开威锋网注册页面

2、移动鼠标至小滑块,一张完整的图片会出现(如下图1)

3、点击鼠标左键,图片中间会出现一个缺块(如下图2)

4、移动小滑块正上方图案至缺块处

5、验证通过

selenium模拟验证的过程

  1. 加载威锋网注册页面
  2. 下载图片1和缺块图片2
  3. 根据两张图片的差异计算平移的距离x
  4. 模拟鼠标点击事件,点击小滑块向右移动x
  5. 验证通过
  6. 详细分析

1、打开chrome浏览器控制台,会发现图1所示的验证码图片并不是极验后台返回的原图。而是由多个div拼接而成(如下图3)

通过图片显示div的style属性可知,极验后台把图片进行切割加错位处理。把素材图片切割成10 * 58大小的52张小图,再进行错位处理。在网页上显示的时候,再通过css的background-position属性对图片进行还原。以上的图1和图2都是经过了这种处理。在这种情况下,使用selenium模拟验证是需要对下载的验证码图片进行还原。如上图3的第一个div.gt_cut_fullbg_slice标签,它的大小为10px * 58px,其中style属性为background-image: url("http://static.geetest.com/pictures/gt/969ffa43c/969ffa43c.webp"); background-position: -157px -58px;会把该属性对应url的图片进行一个平移操作,以左上角为参考,向左平移157px,向上平移58px,图片超出部分不会显示。所以上图1所示图片是由26 * 2个10px * 58px大小的div组成(如下图4)。每一个小方块的大小58 * 10

2、下载图片并还原,上一步骤分析了图片具体的混淆逻辑,具体还原图片的代码实现如下,主要逻辑是把原图裁剪为52张小图,然后拼接成一张完整的图。

/**
 *还原图片
 * @param type
 */
private static void restoreImage(String type) throws IOException {
  //把图片裁剪为2 * 26份
  for(int i = 0; i < 52; i++){
    cutPic(basePath + type +".jpg"
        ,basePath + "result/" + type + i + ".jpg", -moveArray[i][0], -moveArray[i][1], 10, 58);
  }
  //拼接图片
  String[] b = new String[26];
  for(int i = 0; i < 26; i++){
    b[i] = String.format(basePath + "result/" + type + "%d.jpg", i);
  }
  mergeImage(b, 1, basePath + "result/" + type + "result1.jpg");
  //拼接图片
  String[] c = new String[26];
  for(int i = 0; i < 26; i++){
    c[i] = String.format(basePath + "result/" + type + "%d.jpg", i + 26);
  }
  mergeImage(c, 1, basePath + "result/" + type + "result2.jpg");
  mergeImage(new String[]{basePath + "result/" + type + "result1.jpg",
      basePath + "result/" + type + "result2.jpg"}, 2, basePath + "result/" + type + "result3.jpg");
  //删除产生的中间图片
  for(int i = 0; i < 52; i++){
    new File(basePath + "result/" + type + i + ".jpg").deleteOnExit();
  }
  new File(basePath + "result/" + type + "result1.jpg").deleteOnExit();
  new File(basePath + "result/" + type + "result2.jpg").deleteOnExit();
}

还原过程需要注意的是,后台返回错位的图片是312 * 116大小的。而网页上图片div的大小是260 * 116。

3、计算平移距离,遍历图片的每一个像素点,当两张图的R、G、B之差的和大于255,说明该点的差异过大,很有可能就是需要平移到该位置的那个点,代码如下。

BufferedImage fullBI = ImageIO.read(new File(basePath + "result/" + FULL_IMAGE_NAME + "result3.jpg"));
  BufferedImage bgBI = ImageIO.read(new File(basePath + "result/" + BG_IMAGE_NAME + "result3.jpg"));
  for (int i = 0; i < bgBI.getWidth(); i++){
    for (int j = 0; j < bgBI.getHeight(); j++) {
      int[] fullRgb = new int[3];
      fullRgb[0] = (fullBI.getRGB(i, j) & 0xff0000) >> 16;
      fullRgb[1] = (fullBI.getRGB(i, j) & 0xff00) >> 8;
      fullRgb[2] = (fullBI.getRGB(i, j) & 0xff);

      int[] bgRgb = new int[3];
      bgRgb[0] = (bgBI.getRGB(i, j) & 0xff0000) >> 16;
      bgRgb[1] = (bgBI.getRGB(i, j) & 0xff00) >> 8;
      bgRgb[2] = (bgBI.getRGB(i, j) & 0xff);
      if(difference(fullRgb, bgRgb) > 255){
        return i;
      }
    }
  }

4、模拟鼠标移动事件,这一步骤是最关键的步骤,极验验证码后台正是通过移动滑块的轨迹来判断是否为机器所为。整个移动轨迹的过程越随机越好,我这里提供一种成功率较高的移动算法,代码如下。

  public static void move(WebDriver driver, WebElement element, int distance) throws InterruptedException {
    int xDis = distance + 11;
    System.out.println("应平移距离:" + xDis);
    int moveX = new Random().nextInt(8) - 5;
    int moveY = 1;
    Actions actions = new Actions(driver);
    new Actions(driver).clickAndHold(element).perform();
    Thread.sleep(200);
    printLocation(element);
    actions.moveToElement(element, moveX, moveY).perform();
    System.out.println(moveX + "--" + moveY);
    printLocation(element);
    for (int i = 0; i < 22; i++){
      int s = 10;
      if (i % 2 == 0){
        s = -10;
      }
      actions.moveToElement(element, s, 1).perform();
      printLocation(element);
      Thread.sleep(new Random().nextInt(100) + 150);
    }

    System.out.println(xDis + "--" + 1);
    actions.moveByOffset(xDis, 1).perform();
    printLocation(element);
    Thread.sleep(200);
    actions.release(element).perform();
  }

完整代码如下

package com.github.wycm;
import org.apache.commons.io.FileUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.openqa.selenium.By;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class GeettestCrawler {
  private static String basePath = "src/main/resources/";
  private static String FULL_IMAGE_NAME = "full-image";
  private static String BG_IMAGE_NAME = "bg-image";
  private static int[][] moveArray = new int[52][2];
  private static boolean moveArrayInit = false;
  private static String INDEX_URL = "https://passport.feng.com/?r=user/register";
  private static WebDriver driver;

  static {
    System.setProperty("webdriver.chrome.driver", "D:/dev/selenium/chromedriver_V2.30/chromedriver_win32/chromedriver.exe");
    if (!System.getProperty("os.name").toLowerCase().contains("windows")){
      System.setProperty("webdriver.chrome.driver", "/Users/wangyang/workspace/selenium/chromedriver_V2.30/chromedriver");
    }
    driver = new ChromeDriver();
  }

  public static void main(String[] args) throws InterruptedException {
    for (int i = 0; i < 10; i++){
      try {
        invoke();
      } catch (IOException e) {
        e.printStackTrace();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    driver.quit();
  }
  private static void invoke() throws IOException, InterruptedException {
    //设置input参数
    driver.get(INDEX_URL);

    //通过[class=gt_slider_knob gt_show]
    By moveBtn = By.cssSelector(".gt_slider_knob.gt_show");
    waitForLoad(driver, moveBtn);
    WebElement moveElemet = driver.findElement(moveBtn);
    int i = 0;
    while (i++ < 15){
      int distance = getMoveDistance(driver);
      move(driver, moveElemet, distance - 6);
      By gtTypeBy = By.cssSelector(".gt_info_type");
      By gtInfoBy = By.cssSelector(".gt_info_content");
      waitForLoad(driver, gtTypeBy);
      waitForLoad(driver, gtInfoBy);
      String gtType = driver.findElement(gtTypeBy).getText();
      String gtInfo = driver.findElement(gtInfoBy).getText();
      System.out.println(gtType + "---" + gtInfo);
      /**
       * 再来一次:
       * 验证失败:
       */
      if(!gtType.equals("再来一次:") && !gtType.equals("验证失败:")){
        Thread.sleep(4000);
        System.out.println(driver);
        break;
      }
      Thread.sleep(4000);
    }
  }

  /**
   * 移动
   * @param driver
   * @param element
   * @param distance
   * @throws InterruptedException
   */
  public static void move(WebDriver driver, WebElement element, int distance) throws InterruptedException {
    int xDis = distance + 11;
    System.out.println("应平移距离:" + xDis);
    int moveX = new Random().nextInt(8) - 5;
    int moveY = 1;
    Actions actions = new Actions(driver);
    new Actions(driver).clickAndHold(element).perform();
    Thread.sleep(200);
    printLocation(element);
    actions.moveToElement(element, moveX, moveY).perform();
    System.out.println(moveX + "--" + moveY);
    printLocation(element);
    for (int i = 0; i < 22; i++){
      int s = 10;
      if (i % 2 == 0){
        s = -10;
      }
      actions.moveToElement(element, s, 1).perform();
//      printLocation(element);
      Thread.sleep(new Random().nextInt(100) + 150);
    }

    System.out.println(xDis + "--" + 1);
    actions.moveByOffset(xDis, 1).perform();
    printLocation(element);
    Thread.sleep(200);
    actions.release(element).perform();
  }
  private static void printLocation(WebElement element){
    Point point = element.getLocation();
    System.out.println(point.toString());
  }
  /**
   * 等待元素加载,10s超时
   * @param driver
   * @param by
   */
  public static void waitForLoad(final WebDriver driver, final By by){
    new WebDriverWait(driver, 10).until(new ExpectedCondition<Boolean>() {
      public Boolean apply(WebDriver d) {
        WebElement element = driver.findElement(by);
        if (element != null){
          return true;
        }
        return false;
      }
    });
  }

  /**
   * 计算需要平移的距离
   * @param driver
   * @return
   * @throws IOException
   */
  public static int getMoveDistance(WebDriver driver) throws IOException {
    String pageSource = driver.getPageSource();
    String fullImageUrl = getFullImageUrl(pageSource);
    FileUtils.copyURLToFile(new URL(fullImageUrl), new File(basePath + FULL_IMAGE_NAME + ".jpg"));
    String getBgImageUrl = getBgImageUrl(pageSource);
    FileUtils.copyURLToFile(new URL(getBgImageUrl), new File(basePath + BG_IMAGE_NAME + ".jpg"));
    initMoveArray(driver);
    restoreImage(FULL_IMAGE_NAME);
    restoreImage(BG_IMAGE_NAME);
    BufferedImage fullBI = ImageIO.read(new File(basePath + "result/" + FULL_IMAGE_NAME + "result3.jpg"));
    BufferedImage bgBI = ImageIO.read(new File(basePath + "result/" + BG_IMAGE_NAME + "result3.jpg"));
    for (int i = 0; i < bgBI.getWidth(); i++){
      for (int j = 0; j < bgBI.getHeight(); j++) {
        int[] fullRgb = new int[3];
        fullRgb[0] = (fullBI.getRGB(i, j) & 0xff0000) >> 16;
        fullRgb[1] = (fullBI.getRGB(i, j) & 0xff00) >> 8;
        fullRgb[2] = (fullBI.getRGB(i, j) & 0xff);

        int[] bgRgb = new int[3];
        bgRgb[0] = (bgBI.getRGB(i, j) & 0xff0000) >> 16;
        bgRgb[1] = (bgBI.getRGB(i, j) & 0xff00) >> 8;
        bgRgb[2] = (bgBI.getRGB(i, j) & 0xff);
        if(difference(fullRgb, bgRgb) > 255){
          return i;
        }
      }
    }
    throw new RuntimeException("未找到需要平移的位置");
  }
  private static int difference(int[] a, int[] b){
    return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]) + Math.abs(a[2] - b[2]);
  }
  /**
   * 获取move数组
   * @param driver
   */
  private static void initMoveArray(WebDriver driver){
    if (moveArrayInit){
      return;
    }
    Document document = Jsoup.parse(driver.getPageSource());
    Elements elements = document.select("[class=gt_cut_bg gt_show]").first().children();
    int i = 0;
    for(Element element : elements){
      Pattern pattern = Pattern.compile(".*background-position: (.*?)px (.*?)px.*");
      Matcher matcher = pattern.matcher(element.toString());
      if (matcher.find()){
        String width = matcher.group(1);
        String height = matcher.group(2);
        moveArray[i][0] = Integer.parseInt(width);
        moveArray[i++][1] = Integer.parseInt(height);
      } else {
        throw new RuntimeException("解析异常");
      }
    }
    moveArrayInit = true;
  }
  /**
   *还原图片
   * @param type
   */
  private static void restoreImage(String type) throws IOException {
    //把图片裁剪为2 * 26份
    for(int i = 0; i < 52; i++){
      cutPic(basePath + type +".jpg"
          ,basePath + "result/" + type + i + ".jpg", -moveArray[i][0], -moveArray[i][1], 10, 58);
    }
    //拼接图片
    String[] b = new String[26];
    for(int i = 0; i < 26; i++){
      b[i] = String.format(basePath + "result/" + type + "%d.jpg", i);
    }
    mergeImage(b, 1, basePath + "result/" + type + "result1.jpg");
    //拼接图片
    String[] c = new String[26];
    for(int i = 0; i < 26; i++){
      c[i] = String.format(basePath + "result/" + type + "%d.jpg", i + 26);
    }
    mergeImage(c, 1, basePath + "result/" + type + "result2.jpg");
    mergeImage(new String[]{basePath + "result/" + type + "result1.jpg",
        basePath + "result/" + type + "result2.jpg"}, 2, basePath + "result/" + type + "result3.jpg");
    //删除产生的中间图片
    for(int i = 0; i < 52; i++){
      new File(basePath + "result/" + type + i + ".jpg").deleteOnExit();
    }
    new File(basePath + "result/" + type + "result1.jpg").deleteOnExit();
    new File(basePath + "result/" + type + "result2.jpg").deleteOnExit();
  }
  /**
   * 获取原始图url
   * @param pageSource
   * @return
   */
  private static String getFullImageUrl(String pageSource){
    String url = null;
    Document document = Jsoup.parse(pageSource);
    String style = document.select("[class=gt_cut_fullbg_slice]").first().attr("style");
    Pattern pattern = Pattern.compile("url\\(\"(.*)\"\\)");
    Matcher matcher = pattern.matcher(style);
    if (matcher.find()){
      url = matcher.group(1);
    }
    url = url.replace(".webp", ".jpg");
    System.out.println(url);
    return url;
  }
  /**
   * 获取带背景的url
   * @param pageSource
   * @return
   */
  private static String getBgImageUrl(String pageSource){
    String url = null;
    Document document = Jsoup.parse(pageSource);
    String style = document.select(".gt_cut_bg_slice").first().attr("style");
    Pattern pattern = Pattern.compile("url\\(\"(.*)\"\\)");
    Matcher matcher = pattern.matcher(style);
    if (matcher.find()){
      url = matcher.group(1);
    }
    url = url.replace(".webp", ".jpg");
    System.out.println(url);
    return url;
  }
  public static boolean cutPic(String srcFile, String outFile, int x, int y,
                 int width, int height) {
    FileInputStream is = null;
    ImageInputStream iis = null;
    try {
      if (!new File(srcFile).exists()) {
        return false;
      }
      is = new FileInputStream(srcFile);
      String ext = srcFile.substring(srcFile.lastIndexOf(".") + 1);
      Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(ext);
      ImageReader reader = it.next();
      iis = ImageIO.createImageInputStream(is);
      reader.setInput(iis, true);
      ImageReadParam param = reader.getDefaultReadParam();
      Rectangle rect = new Rectangle(x, y, width, height);
      param.setSourceRegion(rect);
      BufferedImage bi = reader.read(0, param);
      File tempOutFile = new File(outFile);
      if (!tempOutFile.exists()) {
        tempOutFile.mkdirs();
      }
      ImageIO.write(bi, ext, new File(outFile));
      return true;
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    } finally {
      try {
        if (is != null) {
          is.close();
        }
        if (iis != null) {
          iis.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
        return false;
      }
    }
  }
  /**
   * 图片拼接 (注意:必须两张图片长宽一致哦)
   * @param files 要拼接的文件列表
   * @param type 1横向拼接,2 纵向拼接
   * @param targetFile 输出文件
   */
  private static void mergeImage(String[] files, int type, String targetFile) {
    int length = files.length;
    File[] src = new File[length];
    BufferedImage[] images = new BufferedImage[length];
    int[][] ImageArrays = new int[length][];
    for (int i = 0; i < length; i++) {
      try {
        src[i] = new File(files[i]);
        images[i] = ImageIO.read(src[i]);
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
      int width = images[i].getWidth();
      int height = images[i].getHeight();
      ImageArrays[i] = new int[width * height];
      ImageArrays[i] = images[i].getRGB(0, 0, width, height, ImageArrays[i], 0, width);
    }
    int newHeight = 0;
    int newWidth = 0;
    for (int i = 0; i < images.length; i++) {
      // 横向
      if (type == 1) {
        newHeight = newHeight > images[i].getHeight() ? newHeight : images[i].getHeight();
        newWidth += images[i].getWidth();
      } else if (type == 2) {// 纵向
        newWidth = newWidth > images[i].getWidth() ? newWidth : images[i].getWidth();
        newHeight += images[i].getHeight();
      }
    }
    if (type == 1 && newWidth < 1) {
      return;
    }
    if (type == 2 && newHeight < 1) {
      return;
    }
    // 生成新图片
    try {
      BufferedImage ImageNew = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
      int height_i = 0;
      int width_i = 0;
      for (int i = 0; i < images.length; i++) {
        if (type == 1) {
          ImageNew.setRGB(width_i, 0, images[i].getWidth(), newHeight, ImageArrays[i], 0,
              images[i].getWidth());
          width_i += images[i].getWidth();
        } else if (type == 2) {
          ImageNew.setRGB(0, height_i, newWidth, images[i].getHeight(), ImageArrays[i], 0, newWidth);
          height_i += images[i].getHeight();
        }
      }
      //输出想要的图片
      ImageIO.write(ImageNew, targetFile.split("\\.")[1], new File(targetFile));

    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
}

pom文件依赖如下

  <dependency>
   <groupId>org.seleniumhq.selenium</groupId>
   <artifactId>selenium-server</artifactId>
   <version>3.0.1</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
  <dependency>
   <groupId>org.jsoup</groupId>
   <artifactId>jsoup</artifactId>
   <version>1.7.2</version>
  </dependency>

最后

完整代码已上传至github,地址:https://github.com/wycm/selenium-geetest-crack

附上一张滑动效果图

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • Java实现仿淘宝滑动验证码研究代码详解
  • Java selenium处理极验滑动验证码示例
  • Java实现滑动验证码的示例代码
(0)

相关推荐

  • Java实现仿淘宝滑动验证码研究代码详解

    通过下面一张图看下要实现的功能,具体详情如下所示: 现在我就来介绍些软件的其它功能.希望大家有所受益. 模拟人为搜索商品 在刷单的时候,不能直接拿到一个商品网址就进入购买页面吧,得模拟人为搜索. 在这一个过程中有两个难点: 1)商品列表的异步加载 ; 2)翻页并且截图; 在园子里,我就不在关公面前耍大刀了. 直接上关键代码: i:搜索商品,并且翻页 public bool? SearchProduct(TaskDetailModel taskDetailData) { bool? result

  • Java selenium处理极验滑动验证码示例

    要爬取一个网站遇到了极验的验证码,这周都在想着怎么破解这个,网上搜了好多知乎上看到有人问了这问题,我按照这思路去大概实现了一下. 1.使用htmlunit(这种方式我没成功,模拟鼠标拖拽后轨迹没生成,可以跳过) 我用的是java,我首先先想到了用直接用htmlunit,我做了点初始化 private void initWebClient() { if (webClient != null) { return; } webClient = new WebClient(BrowserVersion.

  • Java实现滑动验证码的示例代码

    最近滑动验证码在很多网站逐步流行起来,一方面对用户体验来说,比较新颖,操作简单,另一方面相对图形验证码来说,安全性并没有很大的降低.当然到目前为止,没有绝对的安全验证,只是不断增加攻击者的绕过成本. 接下来分析下滑动验证码的核心流程: 后端随机生成抠图和带有抠图阴影的背景图片,后台保存随机抠图位置坐标 前端实现滑动交互,将抠图拼在抠图阴影之上,获取到用户滑动距离值,比如以下示例 前端将用户滑动距离值传入后端,后端校验误差是否在容许范围内. 这里单纯校验用户滑动距离是最基本的校验,出于更高的安全考

  • selenium+java破解极验滑动验证码的示例代码

    摘要 分析验证码素材图片混淆原理,并采用selenium模拟人拖动滑块过程,进而破解验证码. 人工验证的过程 1.打开威锋网注册页面 2.移动鼠标至小滑块,一张完整的图片会出现(如下图1) 3.点击鼠标左键,图片中间会出现一个缺块(如下图2) 4.移动小滑块正上方图案至缺块处 5.验证通过 selenium模拟验证的过程 加载威锋网注册页面 下载图片1和缺块图片2 根据两张图片的差异计算平移的距离x 模拟鼠标点击事件,点击小滑块向右移动x 验证通过 详细分析 1.打开chrome浏览器控制台,会

  • Python破解极验滑动验证码详细步骤

    极验滑动验证码 以上图片是最典型的要属于极验滑动认证了,极验官网:http://www.geetest.com/. 现在极验验证码已经更新到了 3.0 版本,截至 2017 年 7 月全球已有十六万家企业正在使用极验,每天服务响应超过四亿次,广泛应用于直播视频.金融服务.电子商务.游戏娱乐.政府企业等各大类型网站 对于这类验证,如果我们直接模拟表单请求,繁琐的认证参数与认证流程会让你蛋碎一地,我们可以用selenium驱动浏览器来解决这个问题,大致分为以下几个步骤 1.输入用户名,密码 2.点击

  • thinkphp整合系列之极验滑动验证码geetest功能

    给一个央企做官网,登录模块用的thinkphp验证码类.但是2019-6-10到12号,国家要求央企检验官网漏洞,防止黑客攻击,正直贸易战激烈升级时期,所以各事业单位很重视官网安全性,于是乎集团总部就委托了宁波一个专业检测公司用专业工具检测出,后台验证码能用打码工具暴力破解,发函要求整改.so,就有了下面的极速验证图形 官网:http://www.geetest.com/ 一:注册获取key 注册:创建应用:获取key: 二:导入sdk /ThinkPHP/Library/Org/Xb/Geet

  • Python3网络爬虫开发实战之极验滑动验证码的识别

    上节我们了解了图形验证码的识别,简单的图形验证码我们可以直接利用 Tesserocr 来识别,但是近几年又出现了一些新型验证码,如滑动验证码,比较有代表性的就是极验验证码,它需要拖动拼合滑块才可以完成验证,相对图形验证码来说识别难度上升了几个等级,本节来讲解下极验验证码的识别过程. 1. 本节目标 本节我们的目标是用程序来识别并通过极验验证码的验证,其步骤有分析识别思路.识别缺口位置.生成滑块拖动路径,最后模拟实现滑块拼合通过验证. 2. 准备工作 本次我们使用的 Python 库是 Selen

  • Thinkphp极验滑动验证码实现步骤解析

    对于建站的筒子们来说:垃圾广告真是让人深恶痛绝: 为了清净:搞个难以识别的验证码吧:又被用户各种吐槽: 直到后来出现了极验这个滑动的验证码:这真是一个体验好安全高的方案: 官网:http://www.geetest.com/(此处应该有广告费) 示例项目:https://github.com/baijunyao/thinkphp-bjyadmin 一:注册获取key 注册:创建应用:获取key: 二:导入sdk /ThinkPHP/Library/Org/Xb/Geetest.class.php

  • Java实现动态获取图片验证码的示例代码

    本文介绍了Java实现动态获取图片验证码的示例代码,分享给大家,具体如下: import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingEx

  • 基于C#实现图片滑动验证码的示例代码

    目录 图片准备 合成目标 实现 1.创建项目 2.Nuget添加ImageSharp 3.vscode打开 4.引入图片 5.生成out_bg.jpg 6.生成out_slider.png 全部代码 最后 图片准备 hole.png和slider.png为png是因为图片带有透明度. 合成目标 最终为前端生成两张图片: out_slider.png高度为344与背景图等高. 也可以打开滑动验证Demo页面,F12来观察图片. 实现 本机环境为.net 6.0.300-preview.22204.

  • Java web实现动态图片验证码的示例代码

    验证码 防止恶意表单注册 生成验证码图片 定义宽高 int width = 100; int height = 50; 使用BufferedImage再内存中生成图片 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 绘制背景和边框 Graphics g = image.getGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0

随机推荐