W poprzedniej części tej serii zobaczyliśmy, jak rozpocząć pracę z Python Flask i MySQL oraz zaimplementowaliśmy część naszej aplikacji dotyczącą rejestracji użytkowników. W tym samouczku przeniesiemy to na wyższy poziom, wdrażając funkcję logowania i wylogowania w naszej aplikacji.
Pierwsze kroki
Najpierw sklonuj kod źródłowy poprzedniego samouczka z GitHub.
git clone https://github.com/tutsplus/create-a-web-app-from-scratch-using-python-flask-and-mysql/.git
Po sklonowaniu kodu źródłowego przejdź do części 1 katalogu i uruchom serwer.
python app.py
Skieruj swoją przeglądarkę na https://localhost:5000 i powinieneś mieć uruchomioną aplikację.
Tworzenie interfejsu logowania
Przejdź do FlaskApp/szablonów i utwórz nowy plik o nazwie signin.html . Otwórz signin.html i dodaj następujący kod HTML:
<!DOCTYPE html> <html lang="en"> <head> <title>Python Flask Bucket List App - Sign In</title> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" /> <link href="../static/signup.css" rel="stylesheet" /> </head> <body> <div class="container"> <div class="header"> <nav class="border-bottom flex-wrap mb-4 py-3 d-flex justify-content-center" > <a href="/" class="text-dark text-decoration-none mb-3 mb-md-0 d-flex align-items-center me-md-auto" > <span class="fs-4">Python Flask App</span> </a> <ul class="nav nav-pills"> <li class="nav-item"> <a href="/" class="nav-link">Home</a> </li> <li class="nav-item"> <a href="/signup" class="nav-link">Signup</a> </li> <li class="nav-item"> <a href="/signin" class="nav-link active" aria-current="page" >Sign In</a > </li> </ul> </nav> </div> <div class="bg-light rounded-3 mb-4 p-5"> <div class="container-fluid py-5"> <h1 class="text-center fw-bold display-5">Bucket List App</h1> <form class="form-signin" action="/api/validateLogin" method="post"> <label for="inputEmail" class="sr-only">Email address</label> <input type="email" name="inputEmail" id="inputEmail" class="form-control" placeholder="Email address" required autofocus> <label for="inputPassword" class="sr-only">Password</label> <input type="password" name="inputPassword" id="inputPassword" class="form-control" placeholder="Password" required> <button id="btnSignIn" class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button> </form> </div> <footer class="footer"> <p>© Company 2022</p> </footer> </div> </body> </html>
Otwórz app.py i dodaj nową trasę do interfejsu logowania.
@app.route('/signin') def showSignin(): return render_template('signin.html')
Następnie otwórz index.html i signup.html i dodaj href
link do logowania na obu stronach jako /signin
. Zapisz wszystkie zmiany i uruchom ponownie serwer.
python app.py
Skieruj przeglądarkę na http://localhost:5000 i kliknij Zaloguj się link i powinieneś być w stanie zobaczyć stronę logowania.
Wdrażanie logowania
Teraz musimy stworzyć funkcję sprawdzającą logowanie użytkownika. Po kliknięciu Zaloguj się , opublikujemy wprowadzony adres e-mail i hasło do funkcji weryfikacji użytkownika.
Tworzenie procedury przechowywanej
Aby zweryfikować użytkownika, potrzebujemy procedury składowanej MySQL. Stwórz więc procedurę składowaną MySQL, jak pokazano:
DELIMITER $$ CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_validateLogin`( IN p_username VARCHAR(20) ) BEGIN select * from tbl_user where user_username = p_username; END$$ DELIMITER ;
Otrzymamy dane użytkownika na podstawie username
z bazy danych MySQL przy użyciu sp_validateLogin
. Po uzyskaniu zaszyfrowanego hasła zweryfikujemy je z hasłem wprowadzonym przez użytkownika.
Zweryfikuj metodę użytkownika
Utwórz metodę sprawdzania poprawności użytkownika, którą wywołamy, gdy użytkownik prześle formularz:
@app.route('/api/validateLogin',methods=['POST']) def validateLogin(): try: _username = request.form['inputEmail'] _password = request.form['inputPassword'] except Exception as e: return render_template('error.html',error = str(e))
Jak widać w powyższym kodzie, odczytaliśmy opublikowany adres e-mail i hasło w _username
i _password
. Teraz wywołamy sp_validateLogin
procedura z parametrem _username
. Więc utwórz połączenie MySQL wewnątrz validatelogin
metoda:
con = mysql.connect()
Po utworzeniu połączenia utwórz cursor
za pomocą con
połączenie.
cursor = con.cursor()
Używając kursora, wywołaj procedurę składowaną MySQL, jak pokazano:
cursor.callproc('sp_validateLogin',(_username,))
Pobierz pobrane rekordy z kursora, jak pokazano:
data = cursor.fetchall()
Jeśli dane zawierają jakieś rekordy, dopasujemy pobrane hasło z hasłem wprowadzonym przez użytkownika.
if len(data) > 0: if check_password_hash(str(data[0][3]),_password): return redirect('/userhome') else: return render_template('error.html',error = 'Wrong Email address or Password.') else: return render_template('error.html',error = 'Wrong Email address or Password.')
Jak widać w powyższym kodzie, użyliśmy metody o nazwie check_password_hash
aby sprawdzić, czy zwrócone hasło skrótu jest zgodne z hasłem wprowadzonym przez użytkownika. Jeśli wszystko jest w porządku, przekierujemy użytkownika do userHome.html . A jeśli wystąpi jakiś błąd, wyświetlimy error.html z komunikatem o błędzie.
Oto kompletny validateLogin
kod:
@app.route('/api/validateLogin',methods=['POST']) def validateLogin(): try: _username = request.form['inputEmail'] _password = request.form['inputPassword'] # connect to mysql con = mysql.connect() cursor = con.cursor() cursor.callproc('sp_validateLogin',(_username,)) data = cursor.fetchall() if len(data) > 0: if check_password_hash(str(data[0][3]),_password): session['user'] = data[0][0] return redirect('/userHome') else: return render_template('error.html',error = 'Wrong Email address or Password') else: return render_template('error.html',error = 'Wrong Email address or Password') except Exception as e: return render_template('error.html',error = str(e)) finally: cursor.close() con.close()
Utwórz stronę o nazwie userhome.html wewnątrz folderu szablonów i dodaj następujący kod HTML:
<!DOCTYPE html> <html lang="en"> <head> <title>Python Flask Bucket List App - Home</title> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" /> </head> <body> <div class="container"> <div class="header"> <nav class="border-bottom flex-wrap mb-4 py-3 d-flex justify-content-center" > <a href="/" class="text-dark text-decoration-none mb-3 mb-md-0 d-flex align-items-center me-md-auto" > <span class="fs-4">Python Flask App</span> </a> <ul class="nav nav-pills"> <li class="nav-item"> <a href="/userhome" class="nav-link">Home</a> </li> <li class="nav-item"> <a href="/logout" class="nav-link active">Logout</a> </li> </ul> </nav> </div> <div class="bg-light rounded-3 mb-4 p-5"> <div class="container-fluid py-5"> <h1 class="text-center fw-bold display-5">Welcome Home!</h1> </div> </div> <footer class="footer"> <p>© Company 2022</p> </footer> </div> </body> </html>
Utwórz również stronę błędu o nazwie error.html w templates
folder i dodaj następujący kod HTML:
<!DOCTYPE html> <html lang="en"> <head> <title>Error - Python Flask App</title> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" /> </head> <body> <div class="container"> <div class="header"> <nav class="border-bottom flex-wrap mb-4 py-3 d-flex justify-content-center" > <a href="/" class="text-dark text-decoration-none mb-3 mb-md-0 d-flex align-items-center me-md-auto" > <span class="fs-4">Python Flask App</span> </a> <ul class="nav nav-pills"> <li class="nav-item"> <a href="/" class="nav-link">Home</a> </li> <li class="nav-item"> <a href="/signup" class="nav-link">Signup</a> </li> <li class="nav-item"> <a href="/signin" class="nav-link">Sign In</a> </li> </ul> </nav> </div> <div class="bg-light rounded-3 mb-4 p-5"> <div class="container-fluid py-5"> <h1 class="text-center fw-bold display-5">{{error}}</h1> </div> </div> <footer class="footer"> <p>© Company 2022</p> </footer> </div> </body> </html>
Wewnątrz error.html , mamy element, jak pokazano:
<h1 class="text-center fw-bold display-5">{{error}}</h1>
Wartość zmiennej można przekazać z render_template
funkcja i może być ustawiana dynamicznie.
Po pomyślnym zalogowaniu przekierowujemy użytkownika do strony głównej użytkownika, więc musimy utworzyć trasę o nazwie /userHome
jak pokazano:
@app.route('/userHome') def userHome(): return render_template('userHome.html')
Zapisz wszystkie zmiany i uruchom ponownie serwer. Kliknij Zaloguj się link na stronie głównej i spróbuj zalogować się przy użyciu prawidłowego adresu e-mail i hasła. Po pomyślnej weryfikacji użytkownika powinieneś mieć stronę pokazaną poniżej:
W przypadku nieudanej weryfikacji użytkownika, użytkownik zostanie przekierowany na stronę błędu, jak pokazano poniżej:
Tutaj użyliśmy oddzielnej strony błędu, aby wyświetlić błąd. Jest również w porządku, jeśli chcesz użyć tej samej strony do wyświetlenia komunikatu o błędzie.
Ograniczanie nieautoryzowanego dostępu do strony głównej użytkownika
Po pomyślnej weryfikacji użytkownika, użytkownik jest przekierowywany na stronę główną użytkownika. Ale teraz nawet nieautoryzowany użytkownik może wyświetlić stronę główną, po prostu przeglądając adres URL http://localhost:5000/userhome.
Aby ograniczyć dostęp nieautoryzowanego użytkownika, sprawdzimy zmienną sesji, którą ustawimy po pomyślnym zalogowaniu użytkownika. Więc zaimportuj session
z kolby:
from flask import session
Musimy również ustawić tajny klucz dla sesji. Więc w app.py
, po zainicjowaniu aplikacji ustaw tajny klucz, jak pokazano :
app.secret_key = 'why would I tell you my secret key?'
Teraz wewnątrz validateLogin
metody, przed przekierowaniem użytkownika do /userhome
po pomyślnym zalogowaniu ustaw session
zmienna jak pokazano:
session['user'] = data[0][0]
Następnie wewnątrz userhome
metody, sprawdź zmienną sesji przed renderowaniem userhome.html
. Jeśli zmienna sesji nie zostanie znaleziona, przekieruj do strony błędu.
@app.route('/userhome') def userHome(): if session.get('user'): return render_template('userhome.html') else: return render_template('error.html',error = 'Unauthorized Access')
Zapisz wszystkie zmiany i uruchom ponownie serwer. Bez logowania spróbuj przejść do http://localhost:5000/userhome, a ponieważ nie jesteś jeszcze zalogowany, powinieneś zostać przekierowany na stronę błędu.
Wdrażanie wylogowania
Implementacja funkcji wylogowania jest najprostsza. Wszystko, co musimy zrobić, to utworzyć zmienną sesji user
null i przekieruj użytkownika na stronę główną.
Wewnątrz app.py , utwórz nową trasę i metodę logout
jak pokazano:
@app.route('/logout') def logout(): session.pop('user',None) return redirect('/')
Ustawiliśmy już atrybut href przycisku wylogowania na /logout
. Więc zapisz wszystkie zmiany i zrestartuj serwer. Na stronie głównej kliknij Zaloguj się i spróbuj zalogować się przy użyciu prawidłowego adresu e-mail i hasła. Po zalogowaniu kliknij przycisk Wyloguj w domu użytkownika i powinieneś pomyślnie wylogować się z aplikacji.