前言:
上一篇分分享了基于阿里云實(shí)現(xiàn)的短信驗(yàn)證碼文章,考慮到為了防止登錄時(shí),非人工操作,頻繁獲取驗(yàn)證碼,趁熱打鐵,現(xiàn)在添加了圖片驗(yàn)證碼服務(wù)功能。借鑒網(wǎng)上傳統(tǒng)的做法,把實(shí)現(xiàn)這兩個(gè)驗(yàn)證的功能做成有個(gè)獨(dú)立的服務(wù),通過(guò)Http分別請(qǐng)求獲取校驗(yàn)圖片驗(yàn)證碼和短信驗(yàn)證碼。
一、需求描述:
- 圖形驗(yàn)證碼為,短信驗(yàn)證碼為6位純數(shù)字
- 同一系統(tǒng)圖片驗(yàn)證碼緩存中只存在一個(gè),沒有有效期,每次刷新更新舊圖形驗(yàn)證碼
- 短信驗(yàn)證碼有效期2分鐘
- 每個(gè)手機(jī)號(hào)60秒內(nèi)只能發(fā)送一次短信驗(yàn)證碼,在服務(wù)器端執(zhí)行校驗(yàn)
- 同一個(gè)手機(jī)號(hào)在同一時(shí)間內(nèi)可以有多個(gè)有效的短信驗(yàn)證碼,根據(jù)不同系統(tǒng)類型區(qū)分
- 每個(gè)短信驗(yàn)證碼至多可被使用3次,無(wú)論和請(qǐng)求中的驗(yàn)證碼是否匹配,隨后立即作廢,以防止暴力攻擊
- 發(fā)送短信驗(yàn)證碼之前,先驗(yàn)證圖形驗(yàn)證碼是否正確
二、圖片驗(yàn)證碼實(shí)現(xiàn):
生成隨機(jī)驗(yàn)證碼字符串:
/// <summary>
/// 獲取隨機(jī)驗(yàn)證碼
/// </summary>
/// <returns></returns>
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();
}
隨機(jī)驗(yàn)證碼生成驗(yàn)證碼圖片:
/// <summary>
/// 生成隨機(jī)驗(yàn)證碼圖片
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="captchaCode"></param>
/// <returns></returns>
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();
}
}
}
三、短信驗(yàn)證碼實(shí)現(xiàn):
見上篇:
傳送門:基于Aliyun短信驗(yàn)證碼實(shí)現(xiàn)
四、圖片驗(yàn)證碼獲取與校驗(yàn):
獲?。?/h3>
代碼:
/// <summary>
/// 獲取圖片驗(yàn)證碼
/// </summary>
/// <param name="imgCaptchaDto">圖形驗(yàn)證碼請(qǐng)求信息</param>
[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調(diào)用:詳細(xì)調(diào)用參數(shù)和方式見下方接口在線文檔。
校驗(yàn):
代碼:
/// <summary>
/// 驗(yàn)證圖片驗(yàn)證碼
/// </summary>
/// <param name="imgCaptchaDto">圖形驗(yàn)證碼信息</param>
/// <returns></returns>
[HttpPost("img")]
public IActionResult ValidateImageCaptcha(ImgCaptchaDto imgCaptchaDto)
{
bool isCaptchaValid = _captchaService.ValidateImageCaptcha(imgCaptchaDto);
if (isCaptchaValid)
{
HttpResponseDto httpResponseDto = new HttpResponseDto()
{
IsSuccess = true,
Code = StatusCodes.Status200OK,
Message = "圖形驗(yàn)證碼驗(yàn)證成功"
};
var responJson = JsonConvert.SerializeObject(httpResponseDto);
return Ok(responJson);
}
else
{
HttpResponseDto httpResponseDto = new HttpResponseDto()
{
IsSuccess = false,
Code = StatusCodes.Status403Forbidden,
Message = "驗(yàn)證失敗,請(qǐng)輸入正確手機(jī)號(hào)及獲取到的驗(yàn)證碼"
};
var responJson = JsonConvert.SerializeObject(httpResponseDto);
return StatusCode(StatusCodes.Status403Forbidden, responJson);
}
}
Http調(diào)用:詳細(xì)調(diào)用參數(shù)和方式見下方接口在線文檔。
五、短信驗(yàn)證碼獲取與校驗(yàn):
獲?。?/h3>
代碼:
/// <summary>
/// 獲取短信驗(yàn)證碼
/// </summary>
/// <param name="msgCaptchaDto">短信驗(yàn)證碼請(qǐng)求信息</param>
/// <returns></returns>
[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調(diào)用:詳細(xì)調(diào)用參數(shù)和方式見下方接口在線文檔。
校驗(yàn):
代碼:
/// <summary>
/// 驗(yàn)證短信驗(yàn)證碼
/// </summary>
/// <param name="msgCaptchaDto">短信驗(yàn)證碼信息</param>
/// <returns></returns>
[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調(diào)用:詳細(xì)調(diào)用參數(shù)和方式見下方接口在線文檔。
源碼鏈接地址:
Gitee完整實(shí)例地址:
https://gitee.com/mingliang_it/Captcha文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-635389.html
接口在線文檔:
鏈接地址:
https://console-docs.apipost.cn/preview/82c61b0950bae0c8/924487d25ec3df36文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-635389.html
到了這里,關(guān)于圖形驗(yàn)證碼+短信驗(yàn)證碼實(shí)戰(zhàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!