一文詳解Python中的行為驗(yàn)證碼驗(yàn)證功能
前言
最近在開發(fā)行為驗(yàn)證碼,經(jīng)常觸及到關(guān)于驗(yàn)證類型的相關(guān)內(nèi)容。但使用起來不太熟練,閑暇之余,總結(jié)一下我對行為驗(yàn)證碼驗(yàn)證類型的理解。

驗(yàn)證類型概述
滑動(dòng)拼圖
創(chuàng)新行為式驗(yàn)證,輕松一滑完成拼圖,體驗(yàn)極佳,秒速通過驗(yàn)證。簡潔高效,在保障用戶極致體驗(yàn)的同時(shí),抵御機(jī)器風(fēng)險(xiǎn)。適用于追求用戶體驗(yàn)的場景。
# 生成背景圖
basemap1 = Image.open(bg).convert("RGBA") # 背景圖
if basemap1.size != size: # 需要裁切或拉伸
basemap1 = Graphics.crop(basemap1, size[0], size[1])
puzzle1 = Image.open(url_absolute(img)).convert("RGBA") # 方塊圖,蒙板
# 旋轉(zhuǎn)角度
if rotate == 2:
angle = randint(0, 360)
elif rotate == 1:
angle = choice([0, 90, 180, 270])
else:
angle = 0
# angle = 45
if angle: puzzle1 = puzzle1.rotate(angle, resample=Image.Resampling.BILINEAR)
puzzle1.putalpha(ImageEnhance.Brightness(puzzle1.split()[3]).enhance(alpha)) # 設(shè)置透明度,0-1之間
# 產(chǎn)生隨機(jī)位置
img_size = puzzle1.size # 滑動(dòng)圖片尺寸
spacing = 0 # 滑動(dòng)圖片在底圖位置四周間距,暫時(shí)使用0,小圖片中的圖案本身有20px邊距
# 隨機(jī)位置
x = randint(img_size[0] + spacing, size[0] - img_size[0] - spacing)
y = randint(spacing, size[1] - img_size[1] - spacing)
basemap1.paste(puzzle1, (x, y), puzzle1) # 拷貝
# 方塊滑動(dòng)圖
# basemap2 = Image.open(url_absolute(bg)).convert("RGBA")
basemap2 = Image.open(bg).convert("RGBA")
if basemap2.size != size: # 需要裁切或拉伸
basemap2 = Graphics.crop(basemap2, size[0], size[1])
puzzle2 = Image.open(url_absolute(img)).convert("RGBA")
if angle: puzzle2 = puzzle2.rotate(angle, resample=Image.Resampling.BILINEAR) # 旋轉(zhuǎn)
basemap2 = basemap2.crop((x, y, x + img_size[0], y + img_size[1])) # 裁切
puzzle2.paste(basemap2, (0, 0), puzzle2)
# 替換成長條形滑動(dòng)塊
strip = Image.new('RGBA', (img_size[0], size[1]), (255, 255, 255, 0))
strip.paste(puzzle2, (0, y), puzzle2) # 拷貝文字點(diǎn)選
順序點(diǎn)擊圖中文字,全新行為驗(yàn)證,安全性極高,保障驗(yàn)證安全。提高機(jī)器識別難度的同時(shí),保證真實(shí)用戶可讀。適用于安全要求較高的業(yè)務(wù)場景。
def random_character(self, length=None, type=[0, 1, 2, 3], repeat=False):
"""
生成隨機(jī)字符
:param length: 生成的字符長度,幾個(gè)字符
:param type: [0] 數(shù)字,[1] 大寫字母,[2]小寫字母,[3] 特殊字符
:param repeat: 是否允許重復(fù)字符
:return [("A", 1, "大寫字母"), ("8", 0, "數(shù)字"), ("a", 2, "小寫字母"), ("", 3, "高跟鞋") ...]
"""
if length is None: length = self.str_count
# length = 10
# type = [0]
string = "".join(dict([(key, {
0: "2345678923456789",
1: "ABCDEFGHJKLMNQRTY",
2: "abcdefghijkmnqrty",
3: "",
}[key]) for key in type]).values())
r = []
for i in range(length):
if repeat: # 允許重復(fù)
s = choice(string)
t = Inference.char_type(s)
r.append((s, t[0], t[1]))
else:
anti = 0 # 防止死循環(huán),嘗試一定次數(shù)后允許字符重復(fù)
while True:
anti += 1
s = choice(string)
t = Inference.char_type(s)
st = "".join([it[0] for it in r])
if s not in st or anti > 30:
r.append((s, t[0], t[1]))
break
# 替換 n 個(gè)字母為圖形字符
if 3 in type:
index = sample([i for i in range(length)], randint(0, length)) # 隨機(jī)一組索引值:[0, 3, 1]
icon_char = sample(self.icon_str, len(index)) # 隨機(jī)取出 n 組特殊字符
x = 0
for i in index:
# r = Inference.char_replace(r, i, icon_char[x][1])
r[i] = (icon_char[x][1], 3, icon_char[x][2])
x += 1
return r語序點(diǎn)選
根據(jù)中文語義,按順序依次點(diǎn)擊圖中文字,語義理解能力結(jié)合行為軌跡。適用于安全要求較高的業(yè)務(wù)場景。
下面舉例說說的干擾點(diǎn)與干擾線的制作:
# 噪線
for i in range(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())
# 噪點(diǎn)
for i in range(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())字體識別
點(diǎn)擊與其它字符不同字體的文字,用戶僅需一次點(diǎn)擊,即可進(jìn)行安全驗(yàn)證。適用于安全要求超高的業(yè)務(wù)場景。
# 字體識別
if type in (10, 11, 12): # 789生成成語/固定字符
str_count = 1
str_inter = numeric(str_inter, 2, 20) # 干擾字符不能少于2
v_font = sample(ttf, 2) # 隨機(jī)選出兩種字體
string = []
for i in range(str_count + str_inter):
if type in (10, 11, 12): # 字體識別,只使用兩種字體
font_file = v_font[0] if i == 0 else v_font[1]
else: # 隨機(jī)字體
font_file = choice(ttf)
font = ImageFont.truetype(url_absolute(font_file), size=font_size)
# 成語/使用固定字符,前n個(gè)字符使用成語字符
random_char = idiom[i:i+1] if idiom else ""
# 隨機(jī)字符串及補(bǔ)充固定字符時(shí)追加干擾字符
if random_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)
# 隨機(jī)位置
anti = 0 # 防止字體設(shè)置過大或者圖片設(shè)置過小,導(dǎo)致死循環(huán),嘗試一定次數(shù)后允許字符重疊
while True: # 防止文字重疊
anti += 1
x = randint(0, size[0] - font_size)
y = randint(0, size[1] - font_size)
find = True
for s in string:
if abs(x - s[1]) < font_size and abs(y - s[2]) < font_size:
find = False
break
if find or not string or anti > 20: break
# 創(chuàng)建文字圖片,可旋轉(zhuǎn)
str_bg = Image.new("RGBA", (font_size, font_size), (255, 255, 255, 0)) # 文字用空白圖層
str_draw = ImageDraw.Draw(str_bg)
str_draw.text((0, 0), random_char, Word.get_random_color(), font=font) # 添加文字
angle = randint(-75, 75) if rotate else 0 # 是否隨機(jī)角度
str_bg = str_bg.rotate(angle, resample=Image.Resampling.BILINEAR, expand=0) # 隨機(jī)旋轉(zhuǎn)
basemap.paste(str_bg, (x, y), str_bg) # 圖片與文字合并
# 保存隨機(jī)字符及位置
string.append([random_char, x, y, -angle]) # 字符、x、y、角度(正負(fù)轉(zhuǎn)換,轉(zhuǎn)用CSS順時(shí)針旋轉(zhuǎn)形式)空間推理
根據(jù)提示,點(diǎn)擊對應(yīng)的元素。邏輯解題能力結(jié)合圖形符號等元素識別能力。適用于安全要求超高的業(yè)務(wù)場景。
下面舉例幾種驗(yàn)證方式:
def send_color2differ(self):
""" 請點(diǎn)擊一個(gè)顏色不一樣的字符 """
color = self.color_name(2) # 獲取 2 組帶中文名稱的顏色 [('藍(lán)色', '#0000FF'), ]
data = []
for i in range(self.str_count):
# data/在圖片上生成的數(shù)據(jù)
data.append({
"str": self.string[i][0], # 字符內(nèi)容
"X": self.coord[i][0], # x 位置
"Y": self.coord[i][1], # y 位置
"color": color[0][1] if i == 0 else color[1][1],
"angle": self.angle[i],
"icon": True if self.string[i][1] == 3 else False, # 是否為圖形字符
})
# hint/操作說明文字
hint = f'請點(diǎn)擊一個(gè) <i>顏色不一樣</i> 的 <i>{self.string[0][2]}</i>'
str = [(data[0]["str"], data[0]["X"], data[0]["Y"], data[0]["angle"]), ]
return {"data": data, "str": str, "hint": hint}
def send_color2capital(self):
""" 請點(diǎn)擊藍(lán)色字母對應(yīng)的大寫 """
direc = choice([1, 2]) # 隨機(jī)一種方式,大寫 to 小寫/小寫 to 大寫
color = self.color_name() # 獲取 n 組帶中文名稱的顏色 [('藍(lán)色', '#0000FF'), ]
self.string = self.random_character(type=[direc])
data = []
for i in range(self.str_count):
# data/在圖片上生成的數(shù)據(jù)
data.append({
"str": self.string[i][0], # 字符內(nèi)容
"X": self.coord[i][0], # x 位置
"Y": self.coord[i][1], # y 位置
"color": color[i][1],
"angle": self.angle[i],
"icon": True if self.string[i][1] == 3 else False, # 是否為圖形字符
})
data[0]["str"] = data[1]["str"].swapcase()
# hint/操作說明文字
hint = f'請點(diǎn)擊 <i>{color[0][0]}字母</i> 對應(yīng)的 <i>{"大寫" if direc == 1 else "小寫"}</i>'
str = [(data[1]["str"], data[1]["X"], data[1]["Y"], data[1]["angle"]), ]
return {"data": data, "str": str, "hint": hint}以上就是一文詳解Python中的行為驗(yàn)證碼驗(yàn)證功能的詳細(xì)內(nèi)容,更多關(guān)于Python行為驗(yàn)證碼的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
torchtext入門教程必看,帶你輕松玩轉(zhuǎn)文本數(shù)據(jù)處理
這篇文章主要介紹了torchtext入門教程必看,帶你輕松玩轉(zhuǎn)文本數(shù)據(jù)處理,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-05
python3寫的簡單本地文件上傳服務(wù)器實(shí)例
今天小編就為大家分享一篇python3寫的簡單本地文件上傳服務(wù)器實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-06-06
分享2個(gè)方便調(diào)試Python代碼的實(shí)用工具
這篇文章主要介紹了分享方便調(diào)試Python代碼的2個(gè)實(shí)用工具,可以方便展示我們調(diào)試代碼的中間狀態(tài),提升大家的編碼效率,詳細(xì)的介紹需要的小伙伴可以參考一下下面文章內(nèi)容2022-05-05
python SQLAlchemy的Mapping與Declarative詳解
這篇文章主要介紹了python SQLAlchemy的Mapping與Declarative詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
Python實(shí)現(xiàn)進(jìn)度條和時(shí)間預(yù)估的示例代碼
這篇文章主要介紹了Python實(shí)現(xiàn)進(jìn)度條和時(shí)間預(yù)估的代碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
Python實(shí)戰(zhàn)之自動(dòng)發(fā)送郵件的實(shí)現(xiàn)
自動(dòng)發(fā)送郵件能應(yīng)用于許多場景,下面本文就來和大家講講怎么用Python構(gòu)建一個(gè)自動(dòng)發(fā)送郵件的腳本。感興趣的小伙伴可以動(dòng)手嘗試一下2022-05-05
OpenCV圖像識別之相機(jī)校準(zhǔn)Camera?Calibration學(xué)習(xí)
這篇文章主要為大家介紹了OpenCV圖像識別之相機(jī)校準(zhǔn)Camera?Calibration學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05

