快速为树莓派监控摄像头Python MJPG流代码添加密码验证的方法
树莓派监控流密码校验实现方案
你可以直接使用HTTP Basic认证实现需求,仅需对原有代码做少量调整,无需引入数据库或Flask框架,密码直接硬编码在脚本中即可,同时会拦截未授权用户直接访问stream.mjpg地址绕过校验。
修改后完整代码
import io import picamera import logging import socketserver import base64 from threading import Condition from http import server # 硬编码认证凭证,可自行修改用户名和密码 USERNAME = "admin" PASSWORD = "your_custom_password" PAGE="""\ <html> <head> <title>Raspberry Pi - Surveillance Camera</title> </head> <body> <center><h1>Raspberry Pi - Surveillance Camera</h1></center> <center><img src="stream.mjpg" width="640" height="480"></center> </body> </html> """ class StreamingOutput(object): def __init__(self): self.frame = None self.buffer = io.BytesIO() self.condition = Condition() def write(self, buf): if buf.startswith(b'\xff\xd8'): # 新帧生成,复制缓存内容并通知所有客户端 self.buffer.truncate() with self.condition: self.frame = self.buffer.getvalue() self.condition.notify_all() self.buffer.seek(0) return self.buffer.write(buf) class StreamingHandler(server.BaseHTTPRequestHandler): def do_GET(self): # 优先校验认证信息 auth_header = self.headers.get('Authorization') authenticated = False if auth_header and auth_header.startswith('Basic '): try: auth_decoded = base64.b64decode(auth_header.split(' ')[1]).decode('utf-8') req_user, req_pass = auth_decoded.split(':', 1) if req_user == USERNAME and req_pass == PASSWORD: authenticated = True except Exception: pass if not authenticated: self.send_response(401) self.send_header('WWW-Authenticate', 'Basic realm="Raspberry Pi Camera"') self.send_header('Content-Type', 'text/html') self.end_headers() self.wfile.write(b'请输入正确的用户名和密码访问监控') return # 原有业务逻辑保持不变 if self.path == '/': self.send_response(301) self.send_header('Location', '/index.html') self.end_headers() elif self.path == '/index.html': content = PAGE.encode('utf-8') self.send_response(200) self.send_header('Content-Type', 'text/html') self.send_header('Content-Length', len(content)) self.end_headers() self.wfile.write(content) elif self.path == '/stream.mjpg': self.send_response(200) self.send_header('Age', 0) self.send_header('Cache-Control', 'no-cache, private') self.send_header('Pragma', 'no-cache') self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME') self.end_headers() try: while True: with output.condition: output.condition.wait() frame = output.frame self.wfile.write(b'--FRAME\r\n') self.send_header('Content-Type', 'image/jpeg') self.send_header('Content-Length', len(frame)) self.end_headers() self.wfile.write(frame) self.wfile.write(b'\r\n') except Exception as e: logging.warning( 'Removed streaming client %s: %s', self.client_address, str(e)) else: self.send_error(404) self.end_headers() class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer): allow_reuse_address = True daemon_threads = True with picamera.PiCamera(resolution='640x480', framerate=24) as camera: output = StreamingOutput() # 取消下一行注释修改摄像头旋转角度(单位:度) #camera.rotation = 90 camera.start_recording(output, format='mjpeg') try: address = ('', 8000) server = StreamingServer(address, StreamingHandler) server.serve_forever() finally: camera.stop_recording()
自定义页面内密码输入框方案(可选)
如果需要在HTML页面内嵌入密码输入框而非使用浏览器默认弹框,可以调整PAGE模板增加表单提交逻辑,配合Cookie实现校验,仅需额外修改以下部分:
- 将PAGE修改为包含密码输入框的登录页,未校验通过时返回登录页,校验通过后写入Cookie
- 增加
do_POST方法处理密码提交请求 - 所有请求优先校验Cookie有效性
内容的提问来源于stack exchange,提问作者alex
相关产品推荐
相关产品推荐

