【asp.net】asp.net网页验证码生成之“奇葩”方式
网上有不少asp.net cs生成验证码的文档试验了一下,很少能正常工作
于是我想出了一种生成验证码与表单验证分离的架构
好处是因为验证码生成程序分离,可以随时改进验证码生成算法
而不用修改网页代码
坏处是,调用了外部exe增加了服务器的负载
如果大量客户同时登陆,那么服务器和系统将不能正确工作。
先说一下想法:
生成验证码时,用CS调用VB写的EXE文件
VB的EXE在网站服务器目录下生成图片:
pic.bmp和图片答案ans.txt
CS在调用EXE后获取网站目录下图片然后读取答案
在提交表单时将读到的答案与用户填写的字符串进行比对。
关于vb验证码的生成算法,我在这篇帖子中略有叙述
主要算法大家可以参考这里:
【VB】最简单之验证码生成算法
http://www.0xaa55.com/thread-1096-1-1.html
(出处: 技术宅的结界)
这个新的验证码生成程序是在上述程序上改进而成
大致流程:在程序被调用时监测 是否后台运行参数
检测到以后生成验证码到Form的picturebox中
最后将答案输出至文本文件ans.txt,验证码图片用savepicture保
存至当前目录,以供调用。
那么在此贴上这次用的vb程序代码:
VERSION 5.00
Begin VB.Form Form1
Caption = "Form1"
ClientHeight = 2940
ClientLeft = 60
ClientTop = 600
ClientWidth = 4680
LinkTopic = "Form1"
ScaleHeight = 2940
ScaleWidth = 4680
StartUpPosition = 3'窗口缺省
Begin VB.CommandButton Command2
Caption = "OK"
Enabled = 0 'False
Height = 255
Left = 2160
TabIndex = 3
Top = 480
Width = 975
End
Begin VB.TextBox Text1
Height = 285
Left = -120
TabIndex = 2
Top = 480
Width = 2295
End
Begin VB.CommandButton Command1
Caption = "Change"
Height = 495
Left = 2160
TabIndex = 1
Top = 0
Width = 975
End
Begin VB.PictureBox P
AutoRedraw = -1'True
BackColor = &H00FFFFFF&
ForeColor = &H00000000&
Height = 495
Left = 0
ScaleHeight = 435
ScaleWidth = 2115
TabIndex = 0
Top = 0
Width = 2175
End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit '从这里算真正开始
Dim ans As Single
Dim bShutdown As Boolean
Private Sub Command1_Click()
Randomize '初始化随机数生成器
Command2.Enabled = True '免得不输就pass
Dim a As Integer, b As Integer, c(3) As String, d As String
'a放第一个数,b放第二个数,c放操作符,d保存操作符
Dim i As Integer '计数器变量留着待用
c(1) = "+"
c(2) = "-"
c(3) = "*"
a = Int(Rnd * 10 + 1) '第一个随机数
b = Int(Rnd * 10 + 1) '第二个随机数
P.Cls '清屏
'第一个数
P.FontName = Screen.Fonts(Int(Rnd * 15) + 1) '字体名
P.FontSize = Int(Rnd * 16) + 8 '字号
P.FontBold = CBool(Int(Rnd + 1)) '是否粗体
P.FontItalic = CBool(Int(Rnd + 1)) '是否斜体
P.ForeColor = RGB(Int(Rnd * 254 + 1), Int(Rnd * 254 + 1), Int(Rnd * 254 + 1)) '随机颜色
P.BackColor = RGB(Int(Rnd * 254 + 1), Int(Rnd * 254 + 1), Int(Rnd * 254 + 1))
'定位
P.CurrentX = Int(Rnd() * 10) + 10
P.CurrentY = Int(Rnd() * 50) + 1
P.Print CStr(a) '打印
'操作符
P.FontName = Screen.Fonts(Int(Rnd * 15) + 1)
P.FontSize = Int(Rnd * 16) + 8
P.FontBold = CBool(Int(Rnd + 1))
P.FontItalic = CBool(Int(Rnd + 1))
P.ForeColor = RGB(Int(Rnd * 254 + 1), Int(Rnd * 254 + 1), Int(Rnd * 254 + 1))
P.CurrentX = Int(Rnd() * 500) + 500
P.CurrentY = Int(Rnd() * 50) + 1
d = c(Int(Rnd * 3) + 1) '随机操作符
P.Print d
'第二个数字,原理同上,解释略
P.FontName = Screen.Fonts(Int(Rnd * 15) + 1)
P.FontSize = Int(Rnd * 16) + 8
P.FontBold = CBool(Int(Rnd + 1))
P.FontItalic = CBool(Int(Rnd + 1))
P.ForeColor = RGB(Int(Rnd * 254 + 1), Int(Rnd * 254 + 1), Int(Rnd * 254 + 1))
P.CurrentX = Int(Rnd() * 1000) + 1000
P.CurrentY = Int(Rnd() * 50) + 1
P.Print CStr(b)
'瞎画一些线条
For i = 1 To 7
P.ForeColor = RGB(Int(Rnd * 254 + 1), Int(Rnd * 254 + 1), Int(Rnd * 254 + 1))
P.Line (Rnd * P.ScaleWidth, Rnd * P.ScaleWidth)-(Rnd * P.ScaleWidth, Rnd * P.ScaleWidth)
Next
'瞎画一些点
For i = 1 To 100
P.ForeColor = RGB(Int(Rnd * 254 + 1), Int(Rnd * 254 + 1), Int(Rnd * 254 + 1))
P.PSet (Rnd * P.ScaleWidth, Rnd * P.ScaleWidth)
Next
'判定运算,计算结果
Select Case d
Case "+"
ans = a + b
Case "-"
ans = a - b
Case "*"
ans = a * b
End Select
If bShutdown Then
Dim fso As New FileSystemObject
Dim f As TextStream
Set f = fso.OpenTextFile(App.Path & "\ans.txt",
ForWriting, True)
f.Write CStr(ans)
f.Close
SavePicture P.Image, App.Path & "\pic.bmp"
End
End If
End Sub
Private Sub Command2_Click()
If Val(Text1) = ans And Text1 <> "" Then
MsgBox "Pass!", 48
Else
Call Command1_Click
Text1 = ""
End If
End Sub
Private Sub Form_Load()
If InStr(LCase(Command$), "-backstage") <> 0 Then
Me.Visible = False
bShutdown = True
End If
Call Command1_Click
End Sub
以下是网页cs实现的细节:
在网页中验证码图片用ImageButton存贮
使用ImageButton的ImageUrl属性给图片
那么使用Click事件则可以进行图片的改换
后来发现ImageButton的图片不能刷新
使用Response.AddHeader("Refresh", "0"); 刷新页面
图片即可正常显示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
//操作数据库需要的声明
using System.Data;
using System.Configuration;
using System.Collections;
using System.Data.SqlClient;
//调用外部EXE需要的声明
using System.Diagnostics;
using System.IO;
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ImageButton1.ImageUrl = "pic.bmp";//在初始化页面时引入图片
}
protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
GenerateACodeMap();//切换图片时重新加载图片
Response.AddHeader("Refresh", "0"); //刷新页面
}
protected void Button1_Click(object sender, EventArgs e)
{
string conStr = ConfigurationManager.ConnectionStrings["ConnectionStringMain"].ToString();
SqlConnection myConn = new SqlConnection(conStr);
myConn.Open();
string queueStr = "SELECT * FROM AdminsTable WHERE Username = '" + TextBox1.Text + "' AND Password = '" + TextBox2.Text + "'";
SqlCommand myCmd = new SqlCommand(queueStr, myConn);
SqlDataReader myRdr = myCmd.ExecuteReader();
//以上为连接数据库并查询
string currentpath = System.AppDomain.CurrentDomain.BaseDirectory;//获取当前地址
StreamReader sr = new StreamReader(currentpath + "ans.txt");
String vcodeStr = sr.ReadLine();//获取服务器上存储的答案文件
sr.Close();//关闭对文件的访问
if (TextBox3.Text == vcodeStr.Replace("\n", ""))//判断验证码
{
if (myRdr.Read())//如果读到正确用户名与密码
{
Response.Write("<script>window.alert('hello!');</script>");//登陆成功
}
else
{
Response.Write("<script>window.alert('Bad Username Or Password!');</script>");//用户名密码错误
TextBox1.Text = ""; TextBox2.Text = ""; TextBox3.Text = "";
}
}
else
{
Response.Write("<script>window.alert('Bad Verifying Code!');</script>");//验证码错误
}
GenerateACodeMap();//刷新验证码
}
void GenerateACodeMap()//生成验证码
{
System.Diagnostics.ProcessStartInfo p = null;
System.Diagnostics.Process Proc;
string currentpath = System.AppDomain.CurrentDomain.BaseDirectory;
p = new ProcessStartInfo("vcg.exe", "-backstage");//调用EXE给参“后台”
p.WorkingDirectory = currentpath;
p.WindowStyle = ProcessWindowStyle.Normal;
Proc = System.Diagnostics.Process.Start(p);
while (Proc.HasExited == false)//等待直到进程退出
{
if (Proc.HasExited == true)
{
ImageButton1.ImageUrl = "pic.bmp";//获取图片
}
else
{
ImageButton1.ImageUrl = "default.bmp";//获取不到图片 显示缺省图片
}
}
}
}
具体实现:
用vs创建一只asp.net网站,使用cs语言。
建立一个如图页面:
将上述cs代码写入
将vb生成的exe命名为VCG放置在网站根目录下。
这样整个系统便完成了。
哦 天哪 我的代码你肿么了!{:soso_e126:} cyycoish 发表于 2015-5-19 17:49
哦 天哪 我的代码你肿么了!
要学会不断编辑调整帖子……
页:
[1]