现在验证码的形式越来越丰富,今天要实现的是在点击图片中的文字来进行校验的验证码,如图
这种验证码验证是验证鼠标是否选中了图片中文字的位置,以及选择的顺序,产生验证码的时候可以提供一组底图,然后随机获取一张图片,随机选取几个字,然后把文字的顺序打乱,分别随机放到图片的一个位置上,然后记录文字的位置和顺序,验证的时候验证一下文字的位置和顺序即可
验证码图片的类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/// <summary>
/// 二维码图片
/// </summary>
public class VerCodePic
{
/// <summary>
/// 图片链接
/// </summary>
public string PicURL { get ; set ; }
/// <summary>
/// 第一个字位置
/// </summary>
public FontPoint Font1 { get ; set ; }
/// <summary>
/// 第二个字位置
/// </summary>
public FontPoint Font2 { get ; set ; }
/// <summary>
/// 第三个字位置
/// </summary>
public FontPoint Font3 { get ; set ; }
/// <summary>
/// 第四个字位置
/// </summary>
public FontPoint Font4 { get ; set ; }
}
/// <summary>
/// 文字位置
/// </summary>
public class FontPoint
{
public int X { get ; set ; }
public int Y { get ; set ; }
}
|
生成验证码图片验证码的方法,在这个方法中指定了生成的验证码图片中字体大小为20个像素,因为验证码底图的大小是固定的,所以就把验证码底图按照字体的大小分成了若干个网格位置,指定一个文字在图片中的位置时只需要随机获取其中一个网格即可,如果这个网格中没有指定过文字,那就把文字放到这个网格中。
提前设定网格的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
private static ArrayList _FontPoint;
public static ArrayList FontPoint
{
get
{
if (_FontPoint== null )
{
_FontPoint = new ArrayList();
for ( int x=0;x<10;x++)
{
for ( int y=0;y<5;y++)
{
_FontPoint.Add( new Models.FontPoint() { X = x * 28, Y = y * 20 });
}
}
}
return _FontPoint;
}
}
|
我选定的验证码底图为280*100的,所以按照上边的方法将图片分成了若干个网格,在下边设定一个文字位置的时候随机选取其中一个位置,而且给每个字都设定了不一样的颜色
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
/// <summary>
/// 根据文字和图片获取验证码图片
/// </summary>
/// <param name="content"></param>
/// <param name="picFileName"></param>
/// <returns></returns>
public static VerCodePic GetVerCodePic( string content, string picFileName, int fontSize=20)
{
ClassLoger.Info( "FileHelper.GetVerCodePic" , "开始生成二维码" );
Bitmap bmp = new Bitmap(picFileName);
List< int > hlist = new List< int >();
VerCodePic codepic = new VerCodePic();
int i = Utils.GetRandom(0, SystemSet.FontPoint.Count - 1);
codepic.Font1 = SystemSet.FontPoint[i] as FontPoint;
hlist.Add(i);
A: int i2 = Utils.GetRandom(0, SystemSet.FontPoint.Count - 1);
if (hlist.Contains(i2))
goto A;
codepic.Font2 = SystemSet.FontPoint[i2] as FontPoint;
hlist.Add(i2);
B: int i3 = Utils.GetRandom(0, SystemSet.FontPoint.Count - 1);
if (hlist.Contains(i3))
goto B;
hlist.Add(i3);
codepic.Font3 = SystemSet.FontPoint[i3] as FontPoint;
C: int i4 = Utils.GetRandom(0, SystemSet.FontPoint.Count - 1);
if (hlist.Contains(i4))
goto C;
hlist.Add(i4);
codepic.Font4 = SystemSet.FontPoint[i4] as FontPoint; string fileName = (content + "-" + picFileName+ "-" +i+ "|" +i2+ "|" +i3+ "|" +i4).MD5()+Path.GetExtension(picFileName);
string dir = Path.Combine(SystemSet.ResourcesPath, SystemSet.VerCodePicPath);
string filePath = Path.Combine(dir, fileName);
if (File.Exists(filePath))
{
codepic.PicURL = string .Format( "{0}/{1}/{2}" , SystemSet.WebResourcesSite, SystemSet.VerCodePicPath, fileName);
return codepic;
}
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
Graphics g = Graphics.FromImage(bmp);
Font font = new Font( "微软雅黑" , fontSize, GraphicsUnit.Pixel);
SolidBrush sbrush = new SolidBrush(Color.Black);
SolidBrush sbrush1 = new SolidBrush(Color.Peru);
SolidBrush sbrush2 = new SolidBrush(Color.YellowGreen);
SolidBrush sbrush3 = new SolidBrush(Color.SkyBlue);
List< char > fontlist = content.ToList();
ClassLoger.Info( "FileHelper.GetVerCodePic" , fontlist.Count.ToString());
g.DrawString(fontlist[0].TryToString(), font, sbrush, new PointF(codepic.Font1.X, codepic.Font1.Y));
g.DrawString(fontlist[1].TryToString(), font, sbrush1, new PointF(codepic.Font2.X, codepic.Font2.Y));
g.DrawString(fontlist[2].TryToString(), font, sbrush2, new PointF(codepic.Font3.X, codepic.Font3.Y));
g.DrawString(fontlist[3].TryToString(), font, sbrush3, new PointF(codepic.Font4.X, codepic.Font4.Y));
bmp.Save(filePath, ImageFormat.Jpeg);
codepic.PicURL = string .Format( "{0}/{1}/{2}" ,SystemSet.WebResourcesSite, SystemSet.VerCodePicPath, fileName);
return codepic;
}
|
获取图片验证码的api接口,在这个接口中从成语库中随机选取了一个成语,然后随机选取了一个图片,然后调用生成图片验证码的方法,生成了图片验证码,并且把验证码对应的信息缓存在redis中,设定缓存时间,将redis的key作为一个临时令牌随同验证码返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
/// <summary>
/// 获取验证码,有效时间10分钟
/// </summary>
/// <returns></returns>
[HttpGet]
[Route( "vercode" )]
public JsonResult<VerCodePicViewModel> VerCodePic()
{
JsonResult<VerCodePicViewModel> result = new JsonResult<VerCodePicViewModel>();
result.code = 1;
result.msg = "OK" ;
try
{
ClassLoger.Info( "VerCodePic" , "开始获取成语" );
cy_dictBll cybll = new cy_dictBll();
IList<cy_dict> cylist = cybll.GetAllcy_dict();
ClassLoger.Info( "VerCodePic" , cylist.Count.ToString());
int i = Utils.GetRandom(0, cylist.Count-1);
ClassLoger.Info( "VerCodePic" ,i.ToString());
cy_dict cy = cylist[i];
ClassLoger.Info( "VerCodePic成语:" ,cy.chengyu);
VerCodePicViewModel vcvm = new VerCodePicViewModel();
string sourcePic = FileHelper.GetVerCodePicResource();
if (sourcePic.IsNull() || !File.Exists(sourcePic))
{
sourcePic = @"E:\WebResources\images\VerCodePicSource\1.jpg" ;
}
ClassLoger.Info( "VerCodePic图片" ,sourcePic);
VerCodePic codepic = FileHelper.GetVerCodePic(cy.chengyu, sourcePic);
vcvm.content = cy.chengyu;
vcvm.MainPic = codepic.PicURL;
result.Result = vcvm;
string key = cookieKey();
RedisBase.Item_Set(key, codepic);
RedisBase.ExpireEntryAt(key,DateTime.Now.AddMinutes(10));
result.ResultMsg = key;
} catch (Exception ex)
{
ClassLoger.Error( "AccountController.VerCodePic" ,ex);
result.code = -1;
result.msg = "AccountController.VerCodePic发生异常:" +ex.Message;
}
return result;
}
|
效果如图:
图片验证码校验接口参数结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class CheckPicCodeViewModel
{
/// <summary>
/// 客户端令牌
/// </summary>
public string token { get ; set ; }
public double x1 { get ; set ; }
public double x2 { get ; set ; }
public double x3 { get ; set ; }
public double x4 { get ; set ; }
public double y1 { get ; set ; }
public double y2 { get ; set ; }
public double y3 { get ; set ; }
public double y4 { get ; set ; }
}
|
验证码校验接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
/// <summary>
/// 校验图片验证码是否正确
/// </summary>
/// <param name="piccode"></param>
/// <returns></returns>
[HttpPost]
[Route( "checkpiccode" )]
public async Task<IHttpActionResult> CheckPicCode([FromBody]CheckPicCodeViewModel piccode)
{
JsonResult< bool > result = new JsonResult< bool >();
result.code = 1;
result.msg = "OK" ;
if (piccode == null )
{
result.Result = false ;
result.ResultMsg = "参数错误" ;
return Ok(result);
}
if ( string .IsNullOrEmpty(piccode.token) || !RedisBase.ContainsKey(piccode.token))
{
result.Result = false ;
result.ResultMsg = "验证码已过期" ;
return Ok(result);
}
result.Result = await Task.Run< bool >(() => {
bool flag = false ;
VerCodePic codepic = RedisBase.Item_Get<VerCodePic>(piccode.token);
if (Math.Abs(codepic.Font1.X - piccode.x1) > 0.5 || Math.Abs(codepic.Font1.Y - piccode.y1) > 0.5
|| Math.Abs(codepic.Font2.X - piccode.x2) > 0.5 || Math.Abs(codepic.Font2.Y - piccode.y2) > 0.5
|| Math.Abs(codepic.Font3.X - piccode.x3) > 0.5 || Math.Abs(codepic.Font3.Y - piccode.y3) > 0.5
|| Math.Abs(codepic.Font4.X - piccode.x4) > 0.5 || Math.Abs(codepic.Font4.Y - piccode.y4) > 0.5)
{
flag = false ;
result.ResultMsg = "验证码错误" ;
}
else
{
flag = true ;
result.ResultMsg = "验证码正确" ;
}
return flag;
});
return Ok(result);
}
|
传入用户选中的位置和顺序,并对其进行验证。
以上所述是小编给大家介绍的Asp.net Web Api实现图片点击式图片验证码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!
原文链接:http://www.cnblogs.com/liemei/p/7060831.html