做一个简单的图片验证码生成,避免被 ai 简单识别出文本

做一个简单的图片验证码生成,避免被 ai 简单识别出文本

  • 缘由
    • 腾讯云的收费标准
    • 网易的收费标准
  • 编写一个图片验证码生成
    • c# 示例

在这里插入图片描述

缘由

在很多场合,我们会对用户进行一个真实性人工验证,避免各种注册机、机器人之类的,对我们的正常工作造成干扰。

比如说,用户注册时,手机真实性验证时,通过发短信验证手机真实性,而通过图形验证码来验证时由真人操作的。

而现在,由于人工智能技术发展的速度太快了,原有的一些简单的图片信息,会被 ai 简单的就能识别出来。

例如这样的一个图片,其构造十分简单,很容易丧失真实人工操作验证的机能。
在这里插入图片描述

CSDN 文盲老顾的博客,https://blog.csdn.net/superwfei
老顾的个人社区,https://bbs.csdn.net/forums/bfba6c5031e64c13aa7c60eebe858a5f?category=10003&typeId=3364713

当然,网络上也有 captcha.js 这样的非常棒的人机验证手段。

但是。。。验证码这个东西,肯定不是能纯 js 的,要将真实的验证字符隐藏在服务器上,所以纯 js 版的要 pass 掉。

如果不是纯 js 版的, captcha 需要做一些服务器端支持,安装一下 node.js 之类的。

当然,这些都还好说,关键是,现在 captcha.js 收费了?

腾讯云的收费标准

在这里插入图片描述

网易的收费标准

在这里插入图片描述
好家伙,网易这个收费真高,咱小平台根本用不上每小时 3500 次验证的这个档次啊,整个平台日活有没有 3500 真人都不知道呢。

算了,还是自己从新写一个简单的图片验证码生成好了。

编写一个图片验证码生成

基于现在 ai 的先进性能,如之前图片那样的小验证码图片肯定不行了,图片太小,无法放置过多的内容,所有内容基本都是有效的,对 ai 的干扰太少了。

所以,第一个点就是,验证码图片需要放大。只有图片放大了之后,我们才能多放一些东西,比如一些干扰性的内容。

然后,对生成的文本进行内容干扰,老顾在这里就先用一个简单的方式来演示一下。

生成多段文字,其中一段是正确的验证码,用颜色进行区分,类似下图:

在这里插入图片描述在这里插入图片描述

然后,除了干扰字符外,每个字符都进行一定随机角度的旋转。还可以在服务器上安装上类似华文彩云这样的字体,生成镂空字符。

当然,这是一个简单版本的,后续还可以用其他方式干扰,比如设置,选择第几行的字符,比如选择某个范围内的字符(长方形以内、),甚至可以使用问题,比如九月初九,验证码是重阳节这个样子的。

反正,生成图片验证码,怎么生成,就是身为程序员你自己的问题了。

c# 示例

// 因为是用来生成图片,所以,使用 ashx 一般处理程序即可
namespace xxxxxx
    public class Verify_Code : IHttpHandler, IRequiresSessionState
    {
        private List<int> usedColor = new List<int>();
        private List<int> usedSize = new List<int>();
        private List<int> usedFamily = new List<int>();
        private Color[] colors = new Color[] { Color.Black, Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Brown, Color.Yellow, Color.SkyBlue, Color.White, Color.Purple };
        private string colorName = "黑红蓝绿橙棕黄青白紫";
        private string[] family = new string[] { "Arial", "Book Antiqua", "Consolas", "黑体", "华文彩云", "微软雅黑", "楷体", "Verdana" };
        private Random rnd = new Random();
        private int ChoiceColor()
        {
            int r = rnd.Next(colors.Length);
            while (usedColor.Contains(r))
            {
                r = rnd.Next(colors.Length);
            }
            usedColor.Add(r);
            return r;
        }
        public void ProcessRequest(HttpContext context)
        {
            int codeW = 300;
            int codeH = 150;
            string chars = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
            string[] codes = new string[] { RandomString(chars, rnd.Next(3) + 4), RandomString(chars, rnd.Next(3) + 4), RandomString(chars, rnd.Next(3) + 4) };
            Bitmap bmp = new Bitmap(codeW, codeH);
            Graphics g = Graphics.FromImage(bmp);
            g.Clear(Color.Gray);
            for (int i = 0; i < codes.Length; i++)
            {
                string code = codes[i];
                Color c = colors[ChoiceColor()];
                for (int j = 0; j < code.Length; j++)
                {
                    int rotate = rnd.Next(60);
                    rotate = rotate < 30 ? 360 - rotate : rotate - 30;
                    int x = j * (codeW - 20) / code.Length + rnd.Next(20);
                    int y = rnd.Next(96) + 24;
                    DrawRotateTextAtPosition(g, code.Substring(j, 1), rotate, x, y, new Font(family[rnd.Next(family.Length)], rnd.Next(10) + 20, i == codes.Length - 1 ? FontStyle.Bold : FontStyle.Regular), new SolidBrush(c));
                }
                if (i == codes.Length - 1)
                {
                    context.Session["dt_session_code"] = code;
                    CookieHelper.CommonSet("SessionID", CookieHelper.SubDomain, context.Session.SessionID);
                    g.FillRectangle(Brushes.SlateGray, new Rectangle(0, 0, 300, 24));
                    string txt = "请输入" + colorName.Substring(usedColor[usedColor.Count - 1], 1) + "色的字符";
                    for (int j = 0; j < txt.Length; j++)
                    {
                        g.DrawString(txt.Substring(j, 1), new Font("宋体", 16, j == 3 ? FontStyle.Bold : FontStyle.Regular), new SolidBrush(j == 3 ? c : colors[rnd.Next(colors.Length)]), new Point(36 * j, 2));
                    }
                }
            }
            for (int i = 0; i < 500; i++)
            {
                int x3 = rnd.Next(bmp.Width - 1);
                int y3 = rnd.Next(bmp.Height - 25) + 24;
                Color clr = colors[rnd.Next(colors.Length)];
                bmp.SetPixel(x3, y3, clr);
                bmp.SetPixel(x3 + 1, y3, clr);
                bmp.SetPixel(x3, y3 + 1, clr);
                bmp.SetPixel(x3 + 1, y3 + 1, clr);
            }
            context.Response.Buffer = true;
            context.Response.ExpiresAbsolute = DateTime.Now.AddMilliseconds(0.0);
            context.Response.Expires = 0;
            context.Response.CacheControl = "no-cache";
            context.Response.AppendHeader("Pragma", "No-Cache");
            MemoryStream ms = new MemoryStream();
            try
            {
                bmp.Save(ms, ImageFormat.Png);
                context.Response.ClearContent();
                context.Response.ContentType = "image/Png";
                context.Response.BinaryWrite(ms.ToArray());
            }
            finally
            {
                bmp.Dispose();
                g.Dispose();
            }
        }
        private void DrawRotateTextAtPosition(Graphics g, string txt, float cornor, float x, float y, Font f, Brush b)
        {
            var fr = g.MeasureString(txt, f);
            GraphicsState s = g.Save();
            g.ResetTransform();
            g.RotateTransform(cornor);
            g.TranslateTransform(x + fr.Width / 2, y + fr.Height / 2, MatrixOrder.Append);
            g.DrawString(txt, f, b, -fr.Width / 2, -fr.Height / 2);
            g.Restore(s);
        }

        public string RandomString(string charset, int length)
        {
            if (string.IsNullOrEmpty(charset))
            {
                charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            }
            string result = string.Empty;
            for (int i = 0; i < length; i++)
            {
                result += charset.Substring(rnd.Next(charset.Length), 1);
            }
            return result;
        }
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }

这个代码需要将正确的验证码,保存到 session 里,所以,需要对IRequiresSessionState类进行继承。

对于字体来说,如果服务器不存在定义的字体,他会使用 Arial 字体来代替,所以,尽量使用服务器上存在的字体,或者在服务器上安装相应字体。

ChoiceColor 方法,是为了避免选中同样的颜色。

DrawRotateTextAtPosition 方法,则是为了在指定的位置显示旋转后的字符,如果直接使用 RotateTransform 然后直接 DrawString 的话,位置会乱掉,因为旋转的是当前画布。其中 x 轴的坐标,需要设定范围,避免字符前后顺序乱掉。还有就是,角度需要时正数,可以是浮点型。如果向回旋转,即角度小于0度,需要用 360 度加上负角度。

当然,老顾对 ai 也不了解,也不知道,ai 识别图片验证码,能有什么优势。。。

在这里插入图片描述
在这里插入图片描述
大概方式就是这样了,通过多种验证图形,放到一个验证码程序里,随机出一种效果,然后得到验证码即可。

还望各位读者给一些能简单实现的逻辑,用来生成验证码,嘿嘿。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/898800.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

力扣143.重排链表

通过画图分析&#xff0c;可以从反转后链表与原链表中按顺序各自取一个结点来构建结果&#xff0c;不过要注意的这两个链表只会用到一半&#xff0c;结合 链表的中间结点 和 反转链表 进行解题。 /*** Definition for singly-linked list.* struct ListNode {* int val;* …

nginx在access日志中记录请求头和响应头用作用户身份标识分析

在应用系统中&#xff0c;有时将请求的用户信息和身份认证信息放到请求头中&#xff0c;服务器认证通过后&#xff0c;通过cookie返回客户端一个标识&#xff0c;在后续的请求时&#xff0c;客户端需要带上这个cookie&#xff0c;通过这个cookie&#xff0c;服务器就知道请求的…

如何将数据从 AWS S3 导入到 Elastic Cloud - 第 2 部分:Elastic Agent

作者&#xff1a;来自 Elastic Hemendra Singh Lodhi 了解将数据从 AWS S3 提取到 Elastic Cloud 的不同选项。 这是多部分博客系列的第二部分&#xff0c;探讨了将数据从 AWS S3 提取到 Elastic Cloud 的不同选项。 在本博客中&#xff0c;我们将了解如何使用 Elastic Agent…

【C++】进阶:类相关特性的深入探讨

⭐在对C 中类的6个默认成员函数有了初步了解之后&#xff0c;现在我们进行对类相关特性的深入探讨&#xff01; &#x1f525;&#x1f525;&#x1f525;【C】类的默认成员函数&#xff1a;深入剖析与应用&#xff08;上&#xff09; 【C】类的默认成员函数&#xff1a;深入剖…

Linux基础知识和常用基础命令

家目录 每个用户账户的专用目录。家目录的概念为用户提供了一个独立的工作空间&#xff0c;它是用户在文件系统中的主要工作区域&#xff0c;包含了用户的个人文件、配置文件和其他数据。 家目录通常位于 /home/用户名 路径下。例如&#xff0c;如果用户名为 1&#xff0c;那…

[Windows] 很火的开源桌面美化工具 Seelen UI v2.0.2

最近&#xff0c;一款来自Github的开源桌面美化工具突然在网上火了起来&#xff0c;引发了大家的关注&#xff0c;不少小伙伴纷纷开始折腾了起来。而折腾的目的&#xff0c;无非是为了一点点乐趣而已&#xff0c;至于结果如何&#xff0c;并不是最要紧的&#xff0c;反倒是体验…

音频声音怎么调大?将音频声音调大的几个简单方法

音频声音怎么调大&#xff1f;在现代生活中&#xff0c;音频内容无处不在&#xff0c;从在线课程和播客到音乐和电影&#xff0c;音频已经成为我们获取信息和娱乐的重要方式。然而&#xff0c;许多人在使用音频时可能会遇到一个常见问题&#xff1a;音频声音太小&#xff0c;无…

组件通信八种方式(vue3)

一、父传子&#xff08;props&#xff09; 关于Props的相关内容可以参考&#xff1a;Props-CSDN博客 父组件通过 props 向子组件传递数据。适合简单的单向数据流。 <!-- Parent.vue --> <template><Child :message"parentMessage" /> </temp…

2018年-2020年 计算机技术专业 程序设计题(算法题)实战_数组回溯法记录图的路径

阶段性总结&#xff1a; 树的DFS存储一条路径采用定义一个栈的形式 图的DFS和BFS&#xff0c;存储一条路径 采用数组回溯法 文章目录 2018年1.c语言程序设计部分2. 数据结构程序设计部分 2019年1.c语言程序设计部分2. 数据结构程序设计部分 2020年1.c语言程序设计部分2. 数据结…

基于微信小程序的智能校园社区服务推荐系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

Kimi 自带的费曼学习器,妈妈再也不用担心我的学习了

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 AI工具集1&#xff1a;大厂AI工具【共23款…

【经管】比特币与以太坊历史价格数据集(2014.1-2024.5)

一、数据介绍 数据名称&#xff1a;比特币与以太坊历史价格数据集 频率&#xff1a;逐日 时间范围&#xff1a; BTC&#xff1a;2014/9/18-2024/5/1 ETH&#xff1a;2017/11/10-2024/5/1 数据格式&#xff1a;面板数据 二、指标说明 共计7个指标&#xff1a;Date、Open…

安装vue发生异常: idealTree:nodejs: sill idealTree buildDeps

一、异常 C:\>npm install vue -g npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIREDnpm ERR! request to https://registry.npm.taobao.org/vue failed, reason: certificate has expired 二、原因 请求 https://registry.npm.taobao.org 失败&#xff0c;证…

通义灵码:融合创新玩法与探索,重塑LeetCode解题策略

文章目录 关于通义灵码安装指南 通义灵码与LeetCode的结合通义灵码给出优化建议通义灵码给出修改建议通义灵码给出自己的思路 总结 大家好&#xff0c;欢迎大家来到工程师令狐小哥的频道。都说现在的时代是AI程序员的时代。AI程序员标志着程序员的生产力工具已经由原来的搜索式…

JavaSE之String类

文章目录 一、String类常用的构造方法二、常见的四种String对象的比较1.使用比较2.使用equals()方法比较3.使用compareTo()方法比较4.使用compareToIgnoreCase()方法比较 三、字符串的查找四、字符串的转化1.数字和字符串间的转化2.大小写转化3.字符串和数组间的转化 五、字符串…

grafana 配置prometheus

安装prometheus 【linux】麒麟v10安装prometheus监控&#xff08;ARM架构&#xff09;-CSDN博客 登录grafana 访问地址&#xff1a;http://ip:port/login 可以进行 Grafana 相关设置&#xff08;默认账号密码均为 admin&#xff09;。 输入账户密码 添加 Prometheus 数据源…

Codeforces Round 979 (Div. 2)

A. A Gift From Orangutan 题意&#xff1a; 思路&#xff1a; 贪心 模拟 重新排列的数组 -> 最大的元素放第一个位置 &#xff0c;最小的元素放第二个位置 #include<bits/stdc.h> using namespace std; #define lowbit(x) ( x & -x )#define int long long ty…

人类末日?Hinton预言AI恐将夺取地球控制权!

图片来源&#xff1a;Youtube Z Highlights&#xff1a; AI会变得比人类更聪明。我们必须担心它们会想从我们手中夺取控制权&#xff0c;这是我们应该认真思考的问题。 使用AI制造自动化致命武器的风险并不取决于AI是否比我们聪明。这与AI本身可能失控并试图接管的风险是完全…

[论文笔记]HERMES 3 TECHNICAL REPORT

引言 今天带来论文HERMES 3 TECHNICAL REPORT&#xff0c;这篇论文提出了一个强大的工具调用模型&#xff0c;包含了训练方案介绍。同时提出了一个函数调用标准。 为了简单&#xff0c;下文中以翻译的口吻记录&#xff0c;比如替换"作者"为"我们"。 聊天模…

嵌套div导致子区域margin失效问题解决

嵌套div导致子区域margin失效问题解决 现象原因解决方法 现象 <div class"prev"></div> <div class"parent"><div class"child"></div><div class"child"></div> </div> <div cl…