Raspberry Pi Pico W - Webseite mit Login absichern
In diesem Beitrag möchte ich dir zeigen, wie du eine Webseite auf dem Raspberry Pi Pico W mit einem Login Dialog absichern kannst.
Wie du eine Webseite auf dem Raspberry Pi Pico W programmierst und veröffentlichst, habe ich dir bereits im Beitrag Raspberry Pi Pico W â Webseite ins Internet veröffentlichen erlĂ€utert.
Programmieren einer kleinen Seite mit einem Login Dialog
Erstellen wir zunĂ€chst eine kleine Webseite mit den Feldern fĂŒr Benutzername & Passwort und einer SchaltflĂ€che "Login".
Login Dialog fĂŒr den Raspberry Pi Pico W Das Styling in CSS und die JavaScript-Dateien lege ich auf einem Server ab: - http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/css/style.css - http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/js/jquery-3.6.3.min.js - http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/js/functions.js Die Webseite schreibe ich zunĂ€chst in einem normalen Texteditor wie dem Notepad++. Das macht das Testen der Seite deutlich einfacher, da man nicht immer das Programm neu auf den Mikrocontroller schreiben muss. Da wir spĂ€ter den HTML-Code in eine Variable im MicroPython-Code ablegen wollen, dĂŒrfen wir innerhalb des Codes nur die doppelten AnfĂŒhrungszeichen verwenden! Wenn der HTML-Code fertig ist, dann muss dieser noch mit einem Tool komprimiert werden, dazu werden die unnötigen Leerzeilen & ZeilenumbrĂŒche entfernt, hier nutze ich TextFixer. Nachfolgend nun die kleine Seite mit dem formatierten Login Dialog fĂŒr den Raspberry Pi Pico W. Die Felder "{serverIP}" & "{messages}" werden spĂ€ter im MicroPyton-Code durch die IP-Adresse des Mikrocontrollers bzw. der Meldungen ersetzt. Raspberry Pi Pico W
Anmelden
{messages} Wenn wir diesen HTML-Code nun mit TextFixer komprimieren, erhalten wir folgende reduzierten Text: Raspberry Pi Pico W
Anmelden
JavaScript Funktion zum Absenden der Formulardaten Wenn der Benutzer die SchaltflĂ€che "Login" betĂ€tigt, wird eine JavaScript-Funktion ausgefĂŒhrt. Hier nutzte ich wieder jQuery dieses JavaScript Framework ist sehr leichtgewichtig und vor allem sehr gut Dokumentiert. Wenn die Seite fertig geladen ist, dann binden wir an den Login Button die Funktion "click" welche wiederum die Daten aus den Feldern "inpUsername" & "inpPassword" entnimmt und diese wiederum zu einer Adresszeile zusammenfĂŒgt. $( document ).ready(function() { $('#loginBtn').on( "click", function() { var username = $("#inpUsername").val(); var password = $("#inpPassword").val(); window.open("http://"+serverIp+"?username="+username+"&password="+password,'_self'); }); }); Hier finden wir auch wieder unser Feld "serverIp" selcher im HTML-Code als JavaScript Block eingefĂŒgt wurde. Styling per CSS Das Styling des Dialoges habe ich in einer separaten CSS Datei abgelegt, dieses hĂ€lt den eigentlichen HTML-Code sehr schlank und belegt nicht zusĂ€tzlich Speicher auf dem Mikrocontroller. h2{text-align:center;} input{border-radius: 4px;border: 1px solid gray;height: 26px;padding: 3px;} input:focus{background-color:#FEF9E7;outline: none !important;border: 1px solid gray;} input{transition-duration: 0.4s;border-radius: 8px;padding: 10px 24px; background-color: white; color: black; border: 2px solid #008CBA;} input:hover {background-color: #008CBA; color: white;} input, input{width:200px} label{display: inline-block;width: 95px;text-align: right;padding-right: 10px;} .outer{width:250px;margin:0px auto;border:1px solid #BFC9CA;padding:25px;box-shadow: #E5E8E8 6px 6px 2px; margin-top: 60px;border-radius:2px;} .messages{color:red;}
Programmieren in MicroPython auf dem Pi Pico W
Da wir das Frontend soeben fertiggestellt haben, mĂŒssen wir das passende Backend entwickeln. Gerne möchte ich dir hier meine Lösung prĂ€sentieren. Die Werte fĂŒr Benutzername & Passwort werden als GET Parameter an die URL gehĂ€ngt, dies ist ein kleines Sicherheitsrisiko da jeder dieses Passwort lesen kann. Exkurs - Aufbau einer WLAN-Verbindung am Pi Pico W Schauen wir uns zunĂ€chst einmal kurz an wie man eine WLAN-Verbindung am Pi Pico W aufbaut. Den nachfolgenden Code habe ich bereits im Beitrag Raspberry Pi Pico W â Webseite ins Internet veröffentlichen vorgestellt und erlĂ€utert. Jedoch dient dieser als Ausgangsbasis fĂŒr unser Login Dialog. import network import socket import time from machine import Pin ssid = '***' password = '****' wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect(ssid, password) html = 'Raspberry Pi Pico W
Hello World!
' print('waiting for connection...') max_wait = 10 while max_wait > 0: if wlan.status() < 0 or wlan.status() >= 3: break max_wait -= 1 print('.', end='') time.sleep(1) print('') if wlan.status() != 3: raise RuntimeError('network connection failed') else: print('connected') status = wlan.ifconfig() print('ip = ' + status) addr = socket.getaddrinfo('0.0.0.0', 80) s = socket.socket() s.bind(addr) s.listen(1) print('listening on', addr) while True: try: cl, addr = s.accept() print('client connected from', addr) cl.send('HTTP/1.0 200 OKrnContent-type: text/htmlrnrn') cl.send(html) cl.close() except OSError as e: cl.close() print('connection closed')
Login Dialog einbauen
ZunĂ€chst legen wir ein Feld fĂŒr den HTML-Code unserer Seiten an. Zum einen fĂŒr den Login Dialog und eine Seite, wenn der Benutzer erfolgreich eingeloggt wurde. htmlPage = 'Raspberry Pi Pico W
Anmelden
{messages}' loggedInPage = "Raspberry Pi Pico W
Hallo {username}
" Dictionary mit Benutzern Die Benutzer speichern wir in einem Dictionary, wobei der Key der Benutzername ist. users = { "sdraeger": { "password":"draeger" }, "mmustermann": { "password":"mustermann" } } Auslesen der GET Parameter Wenn wir die SchaltflĂ€che Login betĂ€tigen, dann wird der HTTP-Request zusammengebaut mit den Benutzername & Passwort aus den entsprechenden Feldern. Diese Werte finden wir in unserem Code wieder, wenn wir uns das Request Objekt ausgeben: cl, addr = s.accept() print('client connected from', addr) request = cl.recv(1024) request = str(request) print(request) Diesen Text können wir nun parsen und die Werte entnehmen. b'GET /?username=sdraeger&password=draeger HTTP/1.1rnHost: Parsen des Requests Wie man erkennt, beginnen die Parameter am Index 8 und enden mit " HTTP". Hier können wir recht einfach mit Python Logik an diesen Substring gelangen. Dann prĂŒfen wir, ob die SchlĂŒsselwörter "username" und "password" darin enthalten sind. Wenn dieses nicht der Fall ist, soll der Login Dialog ausgeliefert werden. params = request if "username" in params and "password" in params: values = params.split("&") username = values.split("=") password = values.split("=") Wenn diese SchlĂŒsselwörter enthalten sind, werden die Werte geparst. Im nĂ€chsten Schritt muss nun geprĂŒft werden ob der Benutzername als Key im Dictionary "users" hinterlegt ist. if username in users: messages.append("user found") Wenn der Benutzername hinterlegt wurde, dann wird eine Message gespeichert und das Passwort geprĂŒft. Wenn wiederum das Passwort korrekt ist, dann wird die Variable "loginOK" auf True gesetzt andernfalls verbleibt diese auf False. if users ==password: messages.append("login OK") loginOk = True else: messages.append("login fail")
Auswerten des Login Prozesses und ausliefern der Seite
Wenn die Werte geprĂŒft wurden, dann soll eine entsprechende Seite ausgeliefert werden. if loginOk: cl.send(loggedInPage.format(username=username)) else: if messages: loginMessages = messages else: loginMessages = "" cl.send(htmlPage.format(serverIp=serverIpAdress, messages=loginMessages)) In meinem Fall zeige ich dem angemeldeten Benutzer lediglich eine kleine Seite mit einer BegrĂŒĂung an.
Wenn der Login nicht erfolgreich war, dann wir im Dialog eine entsprechende Meldung ausgegeben.
fertiger MicroPython-Code
Hier nun der komplette MicroPython-Code zum einfachen Download als ZIP-Datei oder zum kopieren. Pi Pico W - Login DialogHerunterladen import network import socket import time from machine import Pin ssid = '***' password = '***' users = { "sdraeger": { "password":"draeger" }, "mmustermann": { "password":"mustermann" } } htmlPage = 'Raspberry Pi Pico W
Anmelden
{messages}' loggedInPage = "Raspberry Pi Pico W
Hallo {username}
" wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect(ssid, password) html = 'Raspberry Pi Pico W
Hello World!
' print('waiting for connection...') max_wait = 10 while max_wait > 0: if wlan.status() < 0 or wlan.status() >= 3: break max_wait -= 1 print('.', end='') time.sleep(1) print('') if wlan.status() != 3: raise RuntimeError('network connection failed') else: print('connected') status = wlan.ifconfig() print('ip = ' + status) addr = socket.getaddrinfo('0.0.0.0', 80) s = socket.socket() s.bind(addr) s.listen(1) print('listening on', addr) while True: try: cl, addr = s.accept() print('client connected from', addr) request = cl.recv(1024) request = str(request) print(request) params = request serverIpAdress = status messages = loginOk = False cl.send('HTTP/1.0 200 OKrnContent-type: text/htmlrnrn') if "username" in params and "password" in params: values = params.split("&") username = values.split("=") password = values.split("=") if username in users: messages.append("user found") if users ==password: messages.append("login OK") loginOk = True else: messages.append("login fail") else: messages.append("user not found") if loginOk: cl.send(loggedInPage.format(username=username)) else: if messages: loginMessages = messages else: loginMessages = "" cl.send(htmlPage.format(serverIp=serverIpAdress, messages=loginMessages)) cl.close() except OSError as e: cl.close() print('connection closed') Read the full article

















