世界杯预选赛亚洲区_高达世界杯 - fzxzyy.com

图形验证码+短信验证码实战

- 世界杯奖杯叫什么

前言:

上一篇分分享了基于阿里云实现的短信验证码文章,考虑到为了防止登录时,非人工操作,频繁获取验证码,趁热打铁,现在添加了图片验证码服务功能。借鉴网上传统的做法,把实现这两个验证的功能做成有个独立的服务,通过Http分别请求获取校验图片验证码和短信验证码。

一、需求描述:

图形验证码为,短信验证码为6位纯数字

同一系统图片验证码缓存中只存在一个,没有有效期,每次刷新更新旧图形验证码

短信验证码有效期2分钟

每个手机号60秒内只能发送一次短信验证码,在服务器端执行校验

同一个手机号在同一时间内可以有多个有效的短信验证码,根据不同系统类型区分

每个短信验证码至多可被使用3次,无论和请求中的验证码是否匹配,随后立即作废,以防止暴力攻击

发送短信验证码之前,先验证图形验证码是否正确

二、图片验证码实现:

生成随机验证码字符串:

///

/// 获取随机验证码

///

///

public static string GenerateCaptchaCode()

{

Random rand = new Random();

int maxRand = Letters.Length - 1;

StringBuilder sb = new StringBuilder();

for (int i = 0; i < 4; i++)

{

int index = rand.Next(maxRand);

sb.Append(Letters[index]);

}

return sb.ToString();

}

随机验证码生成验证码图片:

///

/// 生成随机验证码图片

///

///

///

///

///

public static CaptchaResult GenerateCaptcha(int width, int height, string captchaCode)

{

using (Bitmap baseMap = new Bitmap(width, height))

using (Graphics graph = Graphics.FromImage(baseMap))

{

Random rand = new Random();

graph.Clear(GetRandomLightColor());

DrawCaptchaCode();

DrawDisorderLine();

AdjustRippleEffect();

MemoryStream ms = new MemoryStream();

baseMap.Save(ms, ImageFormat.Png);

return new CaptchaResult { CaptchaCode = captchaCode, CaptchaByteData = ms.ToArray(), Timestamp = DateTime.Now };

int GetFontSize(int imageWidth, int captchCodeCount)

{

var averageSize = imageWidth / captchCodeCount;

return Convert.ToInt32(averageSize);

}

Color GetRandomDeepColor()

{

int redlow = 160, greenLow = 100, blueLow = 160;

return Color.FromArgb(rand.Next(redlow), rand.Next(greenLow), rand.Next(blueLow));

}

Color GetRandomLightColor()

{

int low = 180, high = 255;

int nRend = rand.Next(high) % (high - low) + low;

int nGreen = rand.Next(high) % (high - low) + low;

int nBlue = rand.Next(high) % (high - low) + low;

return Color.FromArgb(nRend, nGreen, nBlue);

}

void DrawCaptchaCode()

{

SolidBrush fontBrush = new SolidBrush(Color.Black);

int fontSize = GetFontSize(width, captchaCode.Length);

Font font = new Font(FontFamily.GenericSerif, fontSize, FontStyle.Bold, GraphicsUnit.Pixel);

for (int i = 0; i < captchaCode.Length; i++)

{

fontBrush.Color = GetRandomDeepColor();

int shiftPx = fontSize / 6;

//float x = i * fontSize + rand.Next(-shiftPx, shiftPx) + rand.Next(-shiftPx, shiftPx);

float x = i * fontSize + rand.Next(-shiftPx, shiftPx) / 2;

//int maxY = height - fontSize;

int maxY = height - fontSize * 2;

if (maxY < 0)

{

maxY = 0;

}

float y = rand.Next(0, maxY);

graph.DrawString(captchaCode[i].ToString(), font, fontBrush, x, y);

}

}

void DrawDisorderLine()

{

Pen linePen = new Pen(new SolidBrush(Color.Black), 2);

//for (int i = 0; i < rand.Next(3, 5); i++)

for (int i = 0; i < 2; i++)

{

linePen.Color = GetRandomDeepColor();

Point startPoint = new Point(rand.Next(0, width), rand.Next(0, height));

Point endPoint = new Point(rand.Next(0, width), rand.Next(0, height));

graph.DrawLine(linePen, startPoint, endPoint);

//Point bezierPoint1 = new Point(rand.Next(0, width), rand.Next(0, height));

//Point bezierPoint2 = new Point(rand.Next(0, width), rand.Next(0, height));

//graph.DrawBezier(linePen, startPoint, bezierPoint1, bezierPoint2, endPoint);

}

}

void AdjustRippleEffect()

{

short nWave = 6;

int nWidth = baseMap.Width;

int nHeight = baseMap.Height;

Point[,] pt = new Point[nWidth, nHeight];

for (int x = 0; x < nWidth; ++x)

{

for (int y = 0; y < nHeight; ++y)

{

var xo = nWave * Math.Sin(2.0 * 3.1415 * y / 128.0);

var yo = nWave * Math.Cos(2.0 * 3.1415 * x / 128.0);

var newX = x + xo;

var newY = y + yo;

if (newX > 0 && newX < nWidth)

{

pt[x, y].X = (int)newX;

}

else

{

pt[x, y].X = 0;

}

if (newY > 0 && newY < nHeight)

{

pt[x, y].Y = (int)newY;

}

else

{

pt[x, y].Y = 0;

}

}

}

Bitmap bSrc = (Bitmap)baseMap.Clone();

BitmapData bitmapData = baseMap.LockBits(new Rectangle(0, 0, baseMap.Width, baseMap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

int scanline = bitmapData.Stride;

IntPtr scan0 = bitmapData.Scan0;

IntPtr srcScan0 = bmSrc.Scan0;

unsafe

{

byte* p = (byte*)(void*)scan0;

byte* pSrc = (byte*)(void*)srcScan0;

int nOffset = bitmapData.Stride - baseMap.Width * 3;

for (int y = 0; y < nHeight; ++y)

{

for (int x = 0; x < nWidth; ++x)

{

var xOffset = pt[x, y].X;

var yOffset = pt[x, y].Y;

if (yOffset >= 0 && yOffset < nHeight && xOffset >= 0 && xOffset < nWidth)

{

if (pSrc != null)

{

p[0] = pSrc[yOffset * scanline + xOffset * 3];

p[1] = pSrc[yOffset * scanline + xOffset * 3 + 1];

p[2] = pSrc[yOffset * scanline + xOffset * 3 + 2];

}

}

p += 3;

}

p += nOffset;

}

}

baseMap.UnlockBits(bitmapData);

bSrc.UnlockBits(bmSrc);

bSrc.Dispose();

}

}

}

三、短信验证码实现:

见上篇:

传送门:基于Aliyun短信验证码实现

四、图片验证码获取与校验:

获取:

代码:

///

/// 获取图片验证码

///

/// 图形验证码请求信息

[HttpGet("img")]

public IActionResult GetImageCaptcha([FromQuery]ImgCaptchaDto imgCaptchaDto)

{

var result = _captchaService.GetImageCaptcha(imgCaptchaDto);

var stream = new MemoryStream(result.CaptchaByteData);

return new FileStreamResult(stream, "image/png");

}

Http调用:详细调用参数和方式见下方接口在线文档。

校验:

代码:

///

/// 验证图片验证码

///

/// 图形验证码信息

///

[HttpPost("img")]

public IActionResult ValidateImageCaptcha(ImgCaptchaDto imgCaptchaDto)

{

bool isCaptchaValid = _captchaService.ValidateImageCaptcha(imgCaptchaDto);

if (isCaptchaValid)

{

HttpResponseDto httpResponseDto = new HttpResponseDto()

{

IsSuccess = true,

Code = StatusCodes.Status200OK,

Message = "图形验证码验证成功"

};

var responJson = JsonConvert.SerializeObject(httpResponseDto);

return Ok(responJson);

}

else

{

HttpResponseDto httpResponseDto = new HttpResponseDto()

{

IsSuccess = false,

Code = StatusCodes.Status403Forbidden,

Message = "验证失败,请输入正确手机号及获取到的验证码"

};

var responJson = JsonConvert.SerializeObject(httpResponseDto);

return StatusCode(StatusCodes.Status403Forbidden, responJson);

}

}

Http调用:详细调用参数和方式见下方接口在线文档。

五、短信验证码获取与校验:

获取:

代码:

///

/// 获取短信验证码

///

/// 短信验证码请求信息

///

[HttpGet("msg")]

public IActionResult GetMsgCaptcha([FromQuery]MsgCaptchaDto msgCaptchaDto)

{

var msgSendResult = _captchaService.GetMsgCaptcha(msgCaptchaDto);

if (msgSendResult.Item1)

{

return Ok(msgSendResult.Item2);

}

else

{

return StatusCode(StatusCodes.Status403Forbidden, msgSendResult.Item2);

}

}

Http调用:详细调用参数和方式见下方接口在线文档。

校验:

代码:

///

/// 验证短信验证码

///

/// 短信验证码信息

///

[HttpPost("msg")]

public IActionResult ValidateMsgCaptcha(MsgCaptchaDto msgCaptchaDto)

{

var validateResult = _captchaService.ValidateMsgCaptcha(msgCaptchaDto);

if (validateResult.Item1)

{

HttpResponseDto httpResponseDto = new HttpResponseDto()

{

IsSuccess = true,

Code = StatusCodes.Status200OK,

Message = validateResult.Item2

};

var responJson = JsonConvert.SerializeObject(httpResponseDto);

return Ok(responJson);

}

else

{

HttpResponseDto httpResponseDto = new HttpResponseDto()

{

IsSuccess = false,

Code = StatusCodes.Status403Forbidden,

Message = validateResult.Item2

};

var responJson = JsonConvert.SerializeObject(httpResponseDto);

return StatusCode(StatusCodes.Status403Forbidden, responJson);

}

}

Http调用:详细调用参数和方式见下方接口在线文档。

源码链接地址:

Gitee完整实例地址:

https://gitee.com/mingliang_it/Captcha

接口在线文档:

链接地址:

https://console-docs.apipost.cn/preview/82c61b0950bae0c8/924487d25ec3df36

PMP®报名后多久可以申请缓考?
手机充电接口松动修复全攻略:从简单清洁到专业维修