一、HTML代码
<div id="myModal" class="modal" onsubmit="return captchaSubmit();">
<form action="/verify" method="post"><input type="hidden" id="deviceZz" name="deviceZz" value="value">
<div class="modal-content">
<span class="modal-close">×</span>
<p>
<label for="operator">操作人:</label>
<input type="text" id="operator" name="operator">
</p>
<p>
<label for="password">密码:</label>
<input type="password" id="password" name="password">
</p>
<p>
<img id="captcha" src="/captcha" alt=""/>
<br >
<input type="text" id="captchaInput" placeholder="请输入验证码" name="captchainput">
<button onclick="refreshCaptcha()">刷新</button>
</p>
<div class="button-group">
<button id="submitModal">提交</button>
<button id="cancelModal">取消</button>
</div>
</div>
</form>
</div>
验证码部分的代码
<p>
<img id="captcha" src="/captcha" alt=""/>
<br >
<input type="text" id="captchaInput" placeholder="请输入验证码" name="captchainput">
<button onclick="refreshCaptcha()">刷新</button>
</p>
1.captchaSubmit()包含了在点击提交后,前后端发生交互的一系列操作。包括简单的前端对于操作人密码验证码非空的判断,然后将这些字段打包发给后端,后端进行验证,对数据库中的字段进行匹配,返回json结果,前端收到后判断是否提交表单的一些流程。
2."/verify"用于前端向后端发送数据的,后端验证数据并返回结果
3."/captcha"用于前端需要刷新验证码时,使用get方法从后端获取的验证码图片的src
4.refreshCaptcha()用于刷新验证码,获取src
二、前端js代码
// 模态框中的确定按钮点击事件,写一些因为用户查询未规范填写字段或身份密码验证码输入错误的拦截表单提交的操作
submitModal.onclick=function captchaSubmit() {
var operator = document.getElementById('operator').value;
var password = document.getElementById('password').value;
var captchaInput = document.getElementById('captchaInput').value;
// 检查是否所有输入框都有值
if (!operator || !password || !captchaInput) {
alert('请填写所有字段');
return false; // 阻止表单提交
}
// 创建一个FormData对象来发送数据
var formData = new FormData();
formData.append('operator', operator);
formData.append('password', password);
formData.append('captchainput', captchaInput);
// 使用fetch发送数据到服务器
fetch('/verify', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
//数据成功验证,弹窗自动关闭,方便用户继续进行页面其他操作
modal.style.display = "none";
alert('提交成功');
// 刷新页面
window.location.reload(true);
return true;
} else {
if (data.error === 'operator') {
// 提交失败,清空输入框
document.getElementById('operator').value = '';
document.getElementById('password').value = '';
document.getElementById('captchaInput').value = '';
refreshCaptcha(); // 刷新验证码
alert('身份不存在,请重新输入');
}
else if(data.error === 'password') {
document.getElementById('password').value = '';
document.getElementById('captchaInput').value = '';
refreshCaptcha(); // 刷新验证码
alert('密码错误,请重新输入');
} else if (data.error === 'captcha') {
alert('验证码错误,请重新输入');
document.getElementById('captchaInput').value = '';
refreshCaptcha(); // 刷新验证码
}
}
})
.catch(error => console.error('Error:', error));
// 阻止表单的默认提交行为
return false;
}
//刷新验证码
function refreshCaptcha(){
document.getElementById('captcha').src='/captcha?t='+new Date().getTime();
}
三、后端代码(FLASK)
@yzm_bp.route('/captcha', methods=['get'])
def captcha():
try:
# 生成验证码
code, image = generate_code()
session['captcha'] = code # 存储验证码到session
# 将图像保存到字节流中
image_stream = BytesIO()
image.save(image_stream, 'PNG')
image_stream.seek(0)
# 返回图像给用户
return send_file(image_stream, mimetype='image/png')
except Exception as e:
print("生成错误")
# 验证用户输入
@yzm_bp.route('/verify', methods=['POST'])
def verify():
operator = request.form['operator']
password = request.form['password']
captcha_input = request.form['captchainput']
try:
connection = pymysql.connect(**db_config)
try:
with connection.cursor() as cursor:
sql_list = "select password from operate where operator=%s"
cursor.execute(sql_list, operator)
results = cursor.fetchone()
finally:
connection.close()
except pymysql.MySQLError as e:
print(f"error connecting to mysql:{e}")
# 验证密码
if results is None:
return jsonify({'success': False, 'error': 'operator'})
else:
if password!=results[0]:
return jsonify({'success': False, 'error': 'password'})
else:
# 验证验证码
session_captcha = session.get('captcha') # 从session中获取验证码
if captcha_input.lower() != session_captcha.lower():
return jsonify({'success': False, 'error': 'captcha'})
else:
return jsonify({'success': True, 'error': ''})
四、验证码生成(python)
import os
import random
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
def random_str():
'''
获取一个随机字符, 数字或小写字母
:return:
'''
random_num = str(random.randint(1, 9))
random_low_alpha = chr(random.randint(97, 122))
while random_low_alpha in ['i', 'o', 'l']: # 移除i o l不易识别验证码
random_low_alpha = chr(random.randint(97, 122))
random_char = random.choice([random_num, random_low_alpha])
return random_char
def random_color():
'''
验证码字体颜色
'''
c1 = random.randint(0, 255)
c2 = random.randint(0, 255)
c3 = random.randint(0, 255)
return c1, c2, c3
def generate_picture(width=120, height=35):
'''
生成验证码图片
'''
image = Image.new('RGB', (width, height), random_color())
return image
def draw_str(count, image, font_size):
'''
在图片上写随机字符
:param count: 字符数量
:param image: 图片对象
:param font_size: 字体大小
:return:
'''
draw = ImageDraw.Draw(image)
# 获取一个font字体对象参数是ttf的字体文件的目录,以及字体的大小
font_file = os.path.join('arial.ttf')
font = ImageFont.truetype(font_file, size=font_size)
temp = []
for i in range(count):
random_char = random_str()
draw.text((10 + i * 30, -2), random_char, random_color(), font=font)
temp.append(random_char)
valid_str = ''.join(temp) # 验证码
return valid_str, image
def noise(image, width=120, height=35, line_count=3, point_count=20):
'''
生成图片干扰信息
:param image: 图片对象
:param width: 图片宽度
:param height: 图片高度
:param line_count: 线条数量
:param point_count: 点的数量
:return:
'''
draw = ImageDraw.Draw(image)
for i in range(line_count):
x1 = random.randint(0, width)
x2 = random.randint(0, width)
y1 = random.randint(0, height)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=random_color())
# 画点
for i in range(point_count):
draw.point([random.randint(0, width), random.randint(0, height)], fill=random_color())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=random_color())
return image
def generate_code():
'''
生成验证码
:return:str code
'''
image = generate_picture()
valid_str, image = draw_str(4, image, 35)
image = noise(image)
return valid_str, image
五、结论
我是针对用户对上一个表单的操作进行用户权限的验证写的代码,如果有其他的场景,部分代码可灵活运用。
942

被折叠的 条评论
为什么被折叠?



