基于Flask的人脸识别二次登录:识别通过后如何跳转页面?
解决方案:人脸识别认证后停止流并跳转页面
问题核心在于Flask的流式Response是单向推送,后端无法主动通知前端跳转,必须通过前端轮询状态+后端标记认证结果的配合来实现。以下是具体改造步骤:
1. 后端改造:生成器终止时标记认证状态
修改人脸识别生成器函数,添加匹配计数逻辑,达到指定次数后标记Session状态并终止生成器,同时释放摄像头资源:
def facerec(self, capture, model, encodings, username): match_count = 0 required_matches = 3 # 设定需要匹配的次数 while True: ret, frame = capture.read() if not ret: break # 此处替换为你的人脸识别匹配逻辑,返回True/False表示是否匹配 match_result = self._compare_face_encodings(frame, encodings, model) if match_result: match_count += 1 if match_count >= required_matches: # 标记认证通过 from flask import session session['auth_passed'] = True # 释放摄像头资源 capture.release() cv2.destroyAllWindows() break # 终止生成器 # 编码并返回帧(保留原逻辑) start_time = time.time() ret, buffer = cv2.imencode('.jpg', frame) end = time.time() print(end-start_time,'---encoding image TIME') start_time = time.time() yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + bytearray(buffer) + b'\r\n') cv2.waitKey(25) end = time.time() print(end-start_time,'---yield image TIME')
2. 简化流式路由逻辑
原路由中的while r: return r完全多余,Response会自动迭代生成器,直接返回即可:
@app.route('/clean_feed', methods = ['GET']) def clean_feed(): face_rec = Face_rec(0) capture = cv2.VideoCapture(0) model = "large" cursor = mysql.connection.cursor() cursor.execute('SELECT face_encodings FROM account WHERE username = %s',(session['username'],)) account = cursor.fetchone() if account: encodings = convert_encodings_to_intlist(account) username = [session['username']] # 初始化认证状态 session['auth_passed'] = False # 直接返回流式Response return Response(face_rec.facerec(capture, model, encodings, username), mimetype='multipart/x-mixed-replace; boundary=frame') return render_template('login.html')
3. 添加认证状态检查接口
供前端轮询查询是否完成认证:
@app.route('/check_auth_status') def check_auth_status(): return {'passed': session.get('auth_passed', False)}
4. 前端页面:监听状态并跳转
在显示视频流的页面(如verify.html)中,通过JS定时轮询状态,检测到认证通过后跳转至目标页面:
<!DOCTYPE html> <html> <head> <title>人脸二次验证</title> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> </head> <body> <img id="video-feed" src="{{ url_for('clean_feed') }}"> <script> // 每500ms检查一次认证状态 const checkTimer = setInterval(() => { $.get('/check_auth_status', function(res) { if (res.passed) { clearInterval(checkTimer); // 跳转至认证后的目标页面 window.location.href = '/dashboard'; } }); }, 500); // 额外监听视频流加载失败(生成器终止后可能触发) document.getElementById('video-feed').addEventListener('error', function() { $.get('/check_auth_status', function(res) { if (res.passed) { window.location.href = '/dashboard'; } }); }); </script> </body> </html>
关键注意点
- 确保Flask已开启Session(需设置
SECRET_KEY) - 匹配计数可添加时间窗口限制(如10秒内完成3次匹配),避免误判
- 生成器终止时必须释放摄像头,防止设备占用
内容的提问来源于stack exchange,提问作者Mikołaj Ładny
相关产品推荐
相关产品推荐

