使用kbmmw 实现图形验证码

时间:2023-03-09 07:28:23
使用kbmmw 实现图形验证码

首先感谢图形验证码的提供者  晴空无彩虹  https://blog.****.net/u011784006/article/details/80827181

他用FMX 实现了验证码的生成,我修改成了 VCL 版的。

整个生成验证码的单元,全程推出。

unit uVerifyCode;

interface

uses System.Classes, System.SysUtils,vcl.graphics,Vcl.ExtCtrls, System.IOUtils,
System.UIConsts, System.UITypes, kbmMWGlobal, jpeg,
System.Types;
// 本单元修改自 晴空无彩虹 的单元,表示感谢
type
// 生成验证码组件
TGenerateVerifyCode = class
private const
// 定义字典表,不要零(0),因为零和字母O样子太接近
arrStr: array [ .. ] of char = (
'','','','','','','','','',
'A','B','C','D','E','F','G','H','I',
'J','K','L','M','N','O','P','Q','R',
'S','T','U','V','W','X','Y','Z');
private
FBitmapWidth: integer; // 图片宽度
FBitmapHeight: integer; // 图片高度
FCodeCount: integer; // 取验证码字符的个数,默认是4个字符
FFontName: string; // 字体名称
FMinFontSize: integer; // 最小字体大小
FRandomLineCount: integer; // 背景随机线条数
FTransparency: byte; // 背景随机线条的透明度
FXRandomLen: integer; // X的随机值长度
FYRandomLen: integer; // Y的随机值长度
FLock:TkbmMWLock;
// 画出验证码函数
function VerifyCodeDrawImg(Img:TBitmap): string;
public
constructor Create();
destructor Destroy;override;
procedure GetVerifyCodeAndImage(ImageStream: TStream;
var VerifyCode: string); property Width: integer read FBitmapWidth write FBitmapWidth;
property Height: integer read FBitmapHeight write FBitmapHeight;
property CodeCount: integer read FCodeCount write FCodeCount;
property FontName: string read FFontName write FFontName;
property MinFontSize: integer read FMinFontSize write FMinFontSize;
property RandomLineCount: integer read FRandomLineCount
write FRandomLineCount;
property Transparency: byte read FTransparency write FTransparency;
property XRandomLen: integer read FXRandomLen write FXRandomLen;
property YRandomLen: integer read FYRandomLen write FYRandomLen;
end; function GetVerifyCodeAndImage( ImageStream: TStream):string; implementation function GetVerifyCodeAndImage( ImageStream: TStream):string;
var
gc:TGenerateVerifyCode;
begin
gc:=TGenerateVerifyCode.Create;
try
gc.GetVerifyCodeAndImage(ImageStream, result);
ImageStream.Position:=; finally
gc.Free;
end; end; constructor TGenerateVerifyCode.Create();
begin
inherited;
FBitmapWidth := ;
FBitmapHeight := ;
FCodeCount := ;
FFontName := '宋体';
FMinFontSize := ;
FRandomLineCount := ;
FTransparency := ;
FXRandomLen := ;
FYRandomLen := ;
FLock:=TkbmMWLock.Create; end; // 获取验证码和影像的流数据
destructor TGenerateVerifyCode.Destroy;
begin
FLock.Free;
inherited;
end; procedure TGenerateVerifyCode.GetVerifyCodeAndImage(ImageStream: TStream;
var VerifyCode: string);
var
Img: TBitmap;
jpg:TJPEGImage;
begin Img :=TBitmap.Create;
jpg:=TJPEGImage.Create;
try
Img.Width:=FBitmapWidth;
img.Height:=FBitmapHeight;
// 宽200,高60 VerifyCode := VerifyCodeDrawImg(Img);
jpg.Assign(img);
jpg.SaveToStream(ImageStream);
ImageStream.Position:=;
Img.SaveToStream(ImageStream); // 写到流中
finally freeandnil(Img);
freeandnil(jpg);
end; end; // 画出验证码函数
function TGenerateVerifyCode.VerifyCodeDrawImg(Img: TBitmap): string;
var
I, j, k: integer;
X, Y, W, H: integer;
vLeft: integer;
strResult,c,fn: String;
myrect:Trect;
begin
// 只取4个字符
fn:=Tpath.GetGUIDFileName;
For j := to FCodeCount do
begin
Randomize;
k := Random() mod ;
strResult := strResult + trim(arrStr[k]);
end; img.Canvas.Brush.Style:= bsSolid;
img.Canvas.Brush.Color:=AlphaColorToColor( MakeColor(Random() and $C0,Random() and $C0, Random() and $C0 , FTransparency));
img.Canvas.FillRect(TRect.Create(, ,FBitmapWidth, FBitmapHeight) ); sleep(); Img.Canvas.Font.Name := FFontName; for j := to FRandomLineCount do // 随机画100条线
begin
Randomize; Img.Canvas.Pen.Color :=AlphaColorToColor( MakeColor(Random() and $C0,Random() and $C0, Random() and $C0 , FTransparency));
Img.Canvas.Pen.Width:=; Img.Canvas.PenPos.SetLocation(Random(FBitmapWidth),Random(FBitmapHeight));
Img.Canvas.LineTo(Random(FBitmapWidth), Random(FBitmapHeight));
//
end; vLeft := ;
for I := to length(strResult) do
begin
Randomize;
// 字体大小
Img.Canvas.Font.Size := Random() + FMinFontSize;
// 随机字体颜色
Img.Canvas.Font.Color:= AlphaColorToColor( MakeColor(Random() and $C0,Random() and $C0, Random() and $C0 , FTransparency));
if Img.Canvas.Font.Size < (FMinFontSize + ) then
Img.Canvas.Font.Size := Img.Canvas.Font.Size +;
if Random() = then
Img.Canvas.Font.Style := [TFontStyle.fsBold]
else
Img.Canvas.Font.Style := [TFontStyle.fsItalic];
Img.Canvas.Font.Style:=Img.Canvas.Font.Style+[fsStrikeOut];
// 背景色反色
img.Canvas.Brush.Color:=Img.Canvas.Font.Color xor $FFFFFF;// AlphaColorToColor( MakeColor(Random(256) and $C0,Random(256) and $C0, Random(256) and $C0 , FTransparency));
Img.Canvas.Brush.Style:=bsSolid;
begin
X := Random(FXRandomLen) + vLeft;
Y := Random(FYRandomLen);
W := Img.Canvas.TextWidth(strResult[I])+;
H := Img.Canvas.TextHeight(strResult[I]);
myrect:=TRect.Create(X, Y, X + W, Y + H);
c:=strResult[i];
Img.Canvas.TextRect(myrect,c,[tfCenter] );
vLeft := X + W + ;
end;
end; for j := to do // 随机画5条线
begin
Randomize; Img.Canvas.Pen.Color :=AlphaColorToColor( MakeColor(Random() and $C0,Random() and $C0, Random() and $C0 , FTransparency));
Img.Canvas.Pen.Width:=; Img.Canvas.PenPos.SetLocation(Random(FBitmapWidth),Random(FBitmapHeight));
Img.Canvas.LineTo(Random(FBitmapWidth), Random(FBitmapHeight));
//
end; Result := strResult; // 返回值
end; end.

好了,我们下面在kbmmw 里面实现两个过程,一个过程是生成随机验证图片,并保存验证码在内存中。另外一个过程就是

验证浏览器输入的验证码。本篇文章主要是讨论功能实现,请大家在实际应用中进一步完善,保证信息和数据安全。

[kbmMW_Rest('method:get, path:"getvimage", responseMimeType:"image/jpeg"')]
[kbmMW_Method]
function Getvimage:TkbmMWBytes;
var
vcodelist:TkbmMWThreadDictionary<string,string>;
function TkbmMWCustomHTTPSmartService1.Getvimage: TkbmMWBytes;
var
imgs,js:Tmemorystream;
vcode:string;
hlp,reshlp:TkbmMWRESTTransportStreamHelper;
cookie:TkbmMWHTTPCookie;
stoken:string;
begin
hlp:=TkbmMWRESTTransportStreamHelper(RequestTransportStream.Helper);
imgs:=Tmemorystream.create;
try
vcode:=GetVerifyCodeAndImage(imgs);
Result:=TkbmMWPlatformMarshal.Stream2Bytes(imgs);
stoken:=THashmd5.GetHashString(TkbmMWMixerPasswordGen.Make);
cookie:=TkbmMWHTTPCookie.Create;
cookie.Name:='vcode';
cookie.Value:=stoken;
cookie.Expires:=Tkbmmwdatetime.Null;
reshlp:=TkbmMWRESTTransportStreamHelper(ResponseTransportStream.Helper);
reshlp.Cookies.Add(cookie);
 vcodelist.Add(stoken,vcode); finally
imgs.free; end; end;
 [kbmMW_Rest('method:post, path:"vcodetest", responseMimeType:"text/html"')]
[kbmMW_Method]
function vcodetest:string;
function TkbmMWCustomHTTPSmartService1.vcodetest: string;
var
hlp:TkbmMWRESTTransportStreamHelper;
vl:TkbmMWHTTPCustomValues;
m,invcode,vcode:string;
p:Tbytes;
begin result:='验证失败!'; hlp:=TkbmMWRESTTransportStreamHelper(RequestTransportStream.Helper); m:= hlp.Cookies.ValueByName['vcode']; if m='' then exit; vl:=TkbmMWHTTPQueryValues.Create;
try p:= RequestStream.SaveToBytes; vl.AsString:= Tencoding.ASCII.GetString(p); invcode:= vl.ValueByName['vcode']; if not vcodelist.TryGetValue(m,vcode) then
                  vcode:=''; finally
vl.Free end; if invcode=vcode then
result:='验证通过!'; end;

新建一个HTML 文件 叫 vcodetest.html

<script type="text/javascript" src="/xalionrest/scripts/jquery-1.12.4.min.js"></script>
<script language="javascript" >
$().ready(function(){
$("#img-code").bind( 'click', function () {
$(this).attr('src','/xalionrest/getvimage?t='+Math.random());
}); $("#form1").submit(function(){ if ($("input[name='vcode']").val() == ""){ alert("验证码不能为空!"); $("input[name='vcode']").focus(); return false }
}); });
</script>
<form name="form1" id="form1" method="post" action="/xalionrest/vcodetest" enctype="application/x-www-form-urlencoded" >
<tr>
<td align="center">
<span class="style2">输入验证码</span><input name="vcode" type="text" id="vcode">
<img src="/xalionrest/getvimage" height=60 width=200 id="img-code" class="Verify-Code" style="cursor:pointer" alt="验证码" title="看不清楚?请刷新"> </td>
</tr> <tr> <td align="center">
<br>
<input type="submit" name="Submit" value="提交" >        
<input type="reset" name="Submit" value="重置">
</td>
</tr>
</form>

运行。

浏览器里面输入 http://127.0.0.1/xalionrest/vcodetest.html

使用kbmmw 实现图形验证码

输入验证吗,点提交。

使用kbmmw 实现图形验证码

大年初二,祝大家在猪年,万事如意,大吉大利!

2019.5.18 update :使用了kbmmw 5.09中新加的 TkbmMWThreadDictionary<string,string> 处理 键值,效果更好,更方便。