前言最近,行为验证码的开发经常会涉及到验证类型的相关内容。但是我用起来不是很熟练。闲暇之余,总结一下自己对行为验证码验证类型的理解。验证类型概述刷卡拼图创新行为验证,轻松一键完成拼图,极佳体验,秒过验证。简单高效,在保证极致用户体验的同时,抵御机器风险。适用于追求用户体验的场景。#生成背景图basemap1=Image.open(bg).convert("RGBA")#背景图ifbasemap1.size!=size:#需要裁剪或拉伸basemap1=Graphics.crop(basemap1,size[0],size[1])puzzle1=Image.open(url_absolute(img)).convert("RGBA")#方块图,mask#旋转角度ifrotate==2:angle=randint(0,360)elifrotate==1:angle=choice([0,90,180,270])else:angle=0#angle=45ifangle:puzzle1=puzzle1.rotate(angle,resample=Image.Resampling.BILINEAR)puzzle1.putalpha(ImageEnhance.Brightness(puzzle1.split()[3]).enhance(alpha))#设置透明度,在0-1之间#生成一个随机位置img_size=puzzle1.size#滑动图片大小spacing=0#滑动图片在底面上map位置周围的间距,暂时用0,小图片中的pattern本身有20px的边距#randompositionx=randint(img_size[0]+spacing,size[0]-img_size[0]-spacing)y=randint(间距,尺寸[1]-img_size[1]-间距)basemap1.paste(puzzle1,(x,y),puzzle1)#copy#blockslidingmap#basemap2=Image.open(url_absolute(bg)).convert("RGBA")basemap2=Image.open(bg).convert("RGBA")ifbasemap2.size!=size:#需要裁剪或拉伸basemap2=Graphics.crop(basemap2,size[0],size[1])puzzle2=Image.open(url_absolute(img)).convert("RGBA")ifangle:puzzle2=puzzle2.rotate(angle,resample=Image.Resampling.BILINEAR)#旋转basemap2=basemap2.crop((x,y,x+img_size[0],y+img_size[1]))#剪切puzzle2.paste(basemap2,(0,0),puzzle2)#替换长条滑块strip=Image.new('RGBA',(img_size[0],size[1]),(255,255,255,0))strip.paste(puz??zle2,(0,y),puzzle2)#复制文字点击顺序点击图片中的文字,新的行为验证,安全性高,保证验证安全,增加难度机器识别,保证真实用户的可读性,适用于对安全性要求高的业务场景。defrandom_character(self,length=None,type=[0,1,2,3],repeat=False):"""生成随机字符:paramlength:生成字符的长度,几个字符:paramtype:[0]numbers,[1]大写字母,[2]小写字母,[3]特殊字符:paramrepeat:是否允许重复字符:return[("A",1,"大写字母"),("8",0,"number"),("a",2,"小写字母"),("",3,"高跟鞋")...]"""iflengthisNone:length=self.str_count#length=10#type=[0]string="".join(dict([(key,{0:"2345678923456789",1:"ABCDEFGHJKLMNQRTY",2:"abcdefghijkmnqrty",3:"",}[key])forkeyintype]).values())r=[]foriinrange(length):ifrepeat:#允许重复s=choice(string)t=Inference.char_type(s)r.append((s,t[0],t[1]))else:anti=0#防止无限循环,允许字符在尝试一定次数后重复whileTrue:anti+=1s=choice(string)t=Inference.char_type(s)st="".join([it[0]foritinr])如果s不在st或anti>30:r.append((s,t[0],t[1]))break#用图形字符替换n个字母if3intype:index=sample([iforiinrange(length)],randint(0,length))#一组随机的索引值:[0,3,1]icon_char=sample(self.icon_str,len(index))#随机取出n组特殊字符x=0foriinindex:#r=Inference.char_replace(r,i,icon_char[x][1])r[i]=(icon_char[x][1],3,icon_char[x][2])x+=1returnr点击词序根据中文语义,点击图片顺序,结合语义理解能力行为痕迹适用于对安全性要求高的业务场景。下面举例来说说干扰点和干扰线的制作:#Noiselineforiinrange(line_count):x1=randint(0,size[0])x2=randint(0,size[0])y1=randint(0,size[1])y2=randint(0,size[1])draw.line((x1,y1,x2,y2),fill=Word.get_random_color())#范围内的噪声(point_count):draw.point([randint(0,size[0]),randint(0,size[1])],fill=Word.get_random_color())x=randint(0,size[0])y=randint(0,size[1])draw.arc((x,y,x+4,y+4),0,90,fill=Word.get_random_color())字体识别点击不同字体的文字其他字符的字体,用户只需一键安全验证。适用于对安全性要求极高的业务场景。#字体识别iftypein(10,11,12):#789生成成语/固定字符str_count=1str_inter=numeric(str_inter,2,20)#干扰字符不能小于2v_font=sample(ttf,2)#随机选择两种字体string=[]foriinrange(str_count+str_inter):iftypein(10,11,12):#字体识别,只使用两种字体font_file=v_font[0]ifi==0elsev_font[1]else:#随机字体font_file=choice(ttf)font=ImageFont.truetype(url_absolute(font_file),size=font_size)#成语/使用固定字符,前n个字符使用成语字符random_char=idiom[i:i+1]ifidiomelse""#随机字符串和补充固定字符添加干扰字符ifrandom_char=="":head=randint(0xb0,0xf7)body=randint(0xa1,0xfe)random_char=bytes.fromhex(f'{head:x}{body:x}').decode("gb18030")#print(random_char,font_file)#随机位置anti=0#防止字体设置过大或图片设置过大small,导致死循环,允许字符在尝试一定次数后重叠whileTrue:#防止文本重叠anti+=1x=randint(0,size[0]-font_size)y=randint(0,size[1]-font_size)find=Trueforsinstring:ifabs(x-s[1])
