Skip to content

Technik Blog

Programmieren | Arduino | ESP32 | MicroPython | Python | Raspberry Pi | Raspberry Pi Pico

Menu
  • Smarthome
  • Gartenautomation
  • Arduino
  • ESP32 & Co.
  • Raspberry Pi & Pico
  • Solo Mining
  • Deutsch
  • English
Menu

Raspberry Pi Pico W – Webseite mit Login absichern

Posted on 20. März 20233. Mai 2023 by Stefan Draeger

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
    • JavaScript Funktion zum Absenden der Formulardaten
    • Styling per CSS
  • Programmieren in MicroPython auf dem Pi Pico W
    • Exkurs – Aufbau einer WLAN-Verbindung am Pi Pico W
  • Login Dialog einbauen
    • Dictionary mit Benutzern
    • Auslesen der GET Parameter
      • Parsen des Requests
  • Auswerten des Login Prozesses und ausliefern der Seite
  • fertiger MicroPython-Code

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.

<!DOCTYPE html>
<html>
	<head>
		<title>Raspberry Pi Pico W</title>
		<link rel="stylesheet" type="text/css" href="http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/css/style.css"/>
		<script src="http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/js/jquery-3.6.3.min.js"></script>
		<script src="http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/js/functions.js"></script>		
	</head>
	<script>
	  var serverIp= "{serverIP}";
	</script>
	<body>
		<div class="outer">
			<h2>Anmelden</h2>
			<center>			
			<input type="text" id="inpUsername" name="inpUsername" placeholder="Benutzername"></input><br/><br/>
			<input type="text" id="inpPassword" name="inpPassword" placeholder="Passwort"></input><br/><br/>
			<input type="button" id="loginBtn" value="Login"/>
			</center>
			<br>
			<div class="messages">{messages}</div>			
		</div>		
	</body>
</html>

Wenn wir diesen HTML-Code nun mit TextFixer komprimieren, erhalten wir folgende reduzierten Text:

<!DOCTYPE html><html><head><title>Raspberry Pi Pico W</title><link rel="stylesheet" type="text/css" href="http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/css/style.css"/><script src="http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/js/jquery-3.6.3.min.js"></script><script src="http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/js/functions.js"></script></head><script> var serverIp= "192.168.178.70";</script><body><div class="outer"><h2>Anmelden</h2><center><input type="text" id="inpUsername" name="inpUsername" placeholder="Benutzername"></input><br/><br/><input type="text" id="inpPassword" name="inpPassword" placeholder="Passwort"></input><br/><br/><input type="button" id="loginBtn" value="Login"/></center><br><div class="messages"></div></div></body></html>

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.

<script>
  var serverIp= "{serverIP}";
</script>

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[type=text]{border-radius: 4px;border: 1px solid gray;height: 26px;padding: 3px;}
input[type=text]:focus{background-color:#FEF9E7;outline: none !important;border: 1px solid gray;}
input[type=button]{transition-duration: 0.4s;border-radius: 8px;padding: 10px 24px; background-color: white; color: black; border: 2px solid #008CBA;}
input[type=button]:hover {background-color: #008CBA; color: white;}
input[type=text], input[type=button]{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 = '<!DOCTYPE html><html><head><title>Raspberry Pi Pico W</title></head><body><h1>Hello World!</h1></body></html>'
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[0])

addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]

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 OK\r\nContent-type: text/html\r\n\r\n')
        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 = '<!DOCTYPE html><html><head><title>Raspberry Pi Pico W</title><link rel="stylesheet" type="text/css" href="http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/css/style.css"/><script src="http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/js/jquery-3.6.3.min.js"></script><script src="http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/js/functions.js"></script></head><script> var serverIp= "{serverIp}";</script><body><div class="outer"><h2>Anmelden</h2><center><input type="text" id="inpUsername" name="inpUsername" placeholder="Benutzername"></input><br/><br/><input type="text" id="inpPassword" name="inpPassword" placeholder="Passwort"></input><br/><br/><input type="button" id="loginBtn" value="Login"/></center><br><div class="messages">{messages}</div></div></body></html>'
loggedInPage = "<!DOCTYPE html><html><head><title>Raspberry Pi Pico W</title><link rel='stylesheet' type='text/css' href='http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/css/style.css'/></head><body><h1>Hallo {username}</h1><br/></body></html>"

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.1\r\nHost:

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[8:request.find(' HTTP')]
if "username" in params and "password" in params:           
    values = params.split("&")
    username = values[0].split("=")[1]
    password = values[1].split("=")[1]

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[username]["password"] ==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 = '<!DOCTYPE html><html><head><title>Raspberry Pi Pico W</title><link rel="stylesheet" type="text/css" href="http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/css/style.css"/><script src="http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/js/jquery-3.6.3.min.js"></script><script src="http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/js/functions.js"></script></head><script> var serverIp= "{serverIp}";</script><body><div class="outer"><h2>Anmelden</h2><center><input type="text" id="inpUsername" name="inpUsername" placeholder="Benutzername"></input><br/><br/><input type="text" id="inpPassword" name="inpPassword" placeholder="Passwort"></input><br/><br/><input type="button" id="loginBtn" value="Login"/></center><br><div class="messages">{messages}</div></div></body></html>'
loggedInPage = "<!DOCTYPE html><html><head><title>Raspberry Pi Pico W</title><link rel='stylesheet' type='text/css' href='http://progs.ressourcen-draeger-it.de/raspberrypipicow/login/css/style.css'/></head><body><h1>Hallo {username}</h1><br/></body></html>"

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

html = '<!DOCTYPE html><html><head><title>Raspberry Pi Pico W</title></head><body><h1>Hello World!</h1></body></html>'
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[0])

addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]

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[8:request.find(' HTTP')]
        
        serverIpAdress = status[0]
        messages = []
        
        loginOk = False
        
        cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')  
        
        if "username" in params and "password" in params:           
            values = params.split("&")
            username = values[0].split("=")[1]
            password = values[1].split("=")[1]
            
            if username in users:
               messages.append("user found")
                
               if users[username]["password"] ==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')

Schreibe einen Kommentar Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Fragen oder Feedback?

Du hast eine Idee, brauchst Hilfe oder möchtest Feedback loswerden?
Support-Ticket erstellen

Newsletter abonnieren

Bleib auf dem Laufenden: Erhalte regelmäßig Updates zu neuen Projekten, Tutorials und Tipps rund um Arduino, ESP32 und mehr – direkt in dein Postfach.

Jetzt Newsletter abonnieren

Unterstütze meinen Blog

Wenn dir meine Inhalte gefallen, freue ich mich über deine Unterstützung auf Tipeee.
So hilfst du mit, den Blog am Leben zu halten und neue Beiträge zu ermöglichen.

draeger-it.blog auf Tipeee unterstützen

Vielen Dank für deinen Support!
– Stefan Draeger

Kategorien

Tools

  • Unix-Zeitstempel-Rechner
  • ASCII Tabelle
  • Spannung, Strom, Widerstand und Leistung berechnen
  • Widerstandsrechner
  • 8×8 LED Matrix Tool
  • 8×16 LED Matrix Modul von Keyestudio
  • 16×16 LED Matrix – Generator

Links

Blogverzeichnis Bloggerei.de TopBlogs.de das Original - Blogverzeichnis | Blog Top Liste Blogverzeichnis trusted-blogs.com

Stefan Draeger
Königsberger Str. 13
38364 Schöningen
Tel.: 01778501273
E-Mail: info@draeger-it.blog

Folge mir auf

link zu Fabook
link zu LinkedIn
link zu YouTube
link zu TikTok
link zu Pinterest
link zu Instagram
  • Impressum
  • Datenschutzerklärung
  • Disclaimer
  • Cookie-Richtlinie (EU)
©2025 Technik Blog | Built using WordPress and Responsive Blogily theme by Superb
Cookie-Zustimmung verwalten
Wir verwenden Technologien wie Cookies, um Geräteinformationen zu speichern und/oder darauf zuzugreifen. Wir tun dies, um das Surferlebnis zu verbessern und um personalisierte Werbung anzuzeigen. Wenn Sie diesen Technologien zustimmen, können wir Daten wie das Surfverhalten oder eindeutige IDs auf dieser Website verarbeiten. Wenn Sie Ihre Zustimmung nicht erteilen oder zurückziehen, können bestimmte Funktionen beeinträchtigt werden.
Funktional Immer aktiv
Die technische Speicherung oder der Zugang ist unbedingt erforderlich für den rechtmäßigen Zweck, die Nutzung eines bestimmten Dienstes zu ermöglichen, der vom Teilnehmer oder Nutzer ausdrücklich gewünscht wird, oder für den alleinigen Zweck, die Übertragung einer Nachricht über ein elektronisches Kommunikationsnetz durchzuführen.
Vorlieben
Die technische Speicherung oder der Zugriff ist für den rechtmäßigen Zweck der Speicherung von Präferenzen erforderlich, die nicht vom Abonnenten oder Benutzer angefordert wurden.
Statistiken
Die technische Speicherung oder der Zugriff, der ausschließlich zu statistischen Zwecken erfolgt. Die technische Speicherung oder der Zugriff, der ausschließlich zu anonymen statistischen Zwecken verwendet wird. Ohne eine Vorladung, die freiwillige Zustimmung deines Internetdienstanbieters oder zusätzliche Aufzeichnungen von Dritten können die zu diesem Zweck gespeicherten oder abgerufenen Informationen allein in der Regel nicht dazu verwendet werden, dich zu identifizieren.
Marketing
Die technische Speicherung oder der Zugriff ist erforderlich, um Nutzerprofile zu erstellen, um Werbung zu versenden oder um den Nutzer auf einer Website oder über mehrere Websites hinweg zu ähnlichen Marketingzwecken zu verfolgen.
Optionen verwalten Dienste verwalten Verwalten von {vendor_count}-Lieferanten Lese mehr über diese Zwecke
Einstellungen anzeigen
{title} {title} {title}