posts - 233,  comments - 527,  trackbacks - 0

首先感谢图形验证码的提供者    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;
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

输入验证吗,点提交。

 

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

 

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

 

posted on 2019-02-06 11:00 xalion 阅读(...) 评论(...) 编辑 收藏