使用kbmmw 实现图形验证码

Posted xalion

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用kbmmw 实现图形验证码相关的知识,希望对你有一定的参考价值。

首先感谢图形验证码的提供者    https://blog.csdn.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 [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 里面实现两个过程,一个过程是生成随机验证图片,并保存验证码在内存中。另外一个过程就是

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

[kbmMW_Rest(method:get, path:"getvimage", responseMimeType:"image/jpeg")]
     [kbmMW_Method]
     function Getvimage:TkbmMWBytes;
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];

                vcode:=vcodelist.BeginRead.Values[m];

                vcodelist.EndRead;

      finally
      vl.Free

      end;

    if invcode=vcode then
       result:=验证通过!;
     
end;

 

新建一个HTML 文件 叫 vcodetest.html

<script language="javascript" id="clientEventHandlersJS">
 function B1_onclick() {
 
 if (document.form1.vcode.value==""){
     alert("验证码不能为空!");
     document.form1.vcode.focus();
     return false
      }    
  }      
 
</script>
 
<form name="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="提交" onClick="return B1_onclick()">        
      <input type="reset" name="Submit" value="重置">
    </td>

 

运行。

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

技术图片

输入验证吗,点提交。

 

技术图片

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

 

以上是关于使用kbmmw 实现图形验证码的主要内容,如果未能解决你的问题,请参考以下文章

简单二十行Python代码实现验证码识别技术!

02.实现图形验证码

SpringSecurity-6-基于Filter实现图形验证码

原创干货 | Java代码审计之图形验证码模块

java图形验证码

使用TensorFlow 来实现一个简单的验证码识别过程