首先感謝圖形驗證碼的提供者 晴空無彩虹 https://blog.csdn.net/u011784006/article/details/80827181javascript
他用FMX 實現了驗證碼的生成,我修改爲了 VCL 版的。html
整個生成驗證碼的單元,全程推出。java
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 [0 .. 34] of char = ( '1','2','3','4','5','6','7','8','9', '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:=0; finally gc.Free; end; end; constructor TGenerateVerifyCode.Create(); begin inherited; FBitmapWidth := 200; FBitmapHeight := 60; FCodeCount := 4; FFontName := '宋體'; FMinFontSize := 15; FRandomLineCount := 100; FTransparency := 200; FXRandomLen := 10; FYRandomLen := 8; 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:=0; 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 := 1 to FCodeCount do begin Randomize; k := Random(1000000) mod 35; strResult := strResult + trim(arrStr[k]); end; img.Canvas.Brush.Style:= bsSolid; img.Canvas.Brush.Color:=AlphaColorToColor( MakeColor(Random(256) and $C0,Random(256) and $C0, Random(256) and $C0 , FTransparency)); img.Canvas.FillRect(TRect.Create(0, 0,FBitmapWidth, FBitmapHeight) ); sleep(1); Img.Canvas.Font.Name := FFontName; for j := 1 to FRandomLineCount do // 隨機畫100條線 begin Randomize; Img.Canvas.Pen.Color :=AlphaColorToColor( MakeColor(Random(256) and $C0,Random(256) and $C0, Random(256) and $C0 , FTransparency)); Img.Canvas.Pen.Width:=2; Img.Canvas.PenPos.SetLocation(Random(FBitmapWidth),Random(FBitmapHeight)); Img.Canvas.LineTo(Random(FBitmapWidth), Random(FBitmapHeight)); // 1 end; vLeft := 5; for I := 1 to length(strResult) do begin Randomize; // 字體大小 Img.Canvas.Font.Size := Random(16) + FMinFontSize; // 隨機字體顏色 Img.Canvas.Font.Color:= AlphaColorToColor( MakeColor(Random(256) and $C0,Random(256) and $C0, Random(256) and $C0 , FTransparency)); if Img.Canvas.Font.Size < (FMinFontSize + 10) then Img.Canvas.Font.Size := Img.Canvas.Font.Size +10; if Random(2) = 1 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])+20; 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 + 1; end; end; for j := 1 to 5 do // 隨機畫5條線 begin Randomize; Img.Canvas.Pen.Color :=AlphaColorToColor( MakeColor(Random(256) and $C0,Random(256) and $C0, Random(256) and $C0 , FTransparency)); Img.Canvas.Pen.Width:=1; Img.Canvas.PenPos.SetLocation(Random(FBitmapWidth),Random(FBitmapHeight)); Img.Canvas.LineTo(Random(FBitmapWidth), Random(FBitmapHeight)); // 1 end; Result := strResult; // 返回值 end; end.
好了,咱們下面在kbmmw 裏面實現兩個過程,一個過程是生成隨機驗證圖片,並保存驗證碼在內存中。另一個過程就是jquery
驗證瀏覽器輸入的驗證碼。本篇文章主要是討論功能實現,請你們在實際應用中進一步完善,保證信息和數據安全。vim
[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.htmlcookie
輸入驗證嗎,點提交。app
大年初二,祝你們在豬年,萬事如意,大吉大利!dom
2019.5.18 update :使用了kbmmw 5.09中新加的 TkbmMWThreadDictionary<string,string> 處理 鍵值,效果更好,更方便。