One place for hosting & domains

      FlaskLogin

      Cara Menambah Autentikasi pada Aplikasi Anda dengan Flask-Login


      Pengantar

      Mengizinkan pengguna untuk log masuk ke aplikasi Anda adalah salah satu fitur paling umum yang akan ditambahkan ke aplikasi web Anda. Artikel ini akan membahas cara menambah autentikasi ke aplikasi Flask Anda dengan paket Flask-Login.

      Gif animasi dari aplikasi Flask dan kotak log masuk

      Kita akan membangun beberapa laman pendaftaran dan log masuk yang memungkinkan pengguna untuk log masuk dan mengakses laman-laman yang terlindungi, sedangkan pengguna yang tidak log masuk tidak dapat melihatnya. Kita akan mengambil informasi dari model pengguna dan menampilkannya di laman terlindungi kita ketika pengguna log masuk untuk menyimulasikan tampilan profil.

      Kita akan membahas yang berikut dalam artikel ini:

      • Menggunakan pustaka Flask-Login untuk manajemen sesi
      • Menggunakan utilitas Flash bawaan untuk melakukan hash kata sandi
      • Menambah laman terlindungi di aplikasi kita hanya untuk pengguna yang log masuk
      • Menggunakan Flask-SQLAlchemy untuk menciptakan model pengguna
      • Menciptakan formulir pendaftaran dan log masuk bagi pengguna kita untuk menciptakan akun dan log masuk
      • Memberikan pesan kesalahan flash ke pengguna ketika ada yang salah
      • Menggunakan informasi dari akun pengguna untuk menampilkan laman profil

      Kode sumber untuk proyek ini tersedia di GitHub.

      Prasyarat

      Untuk mengikuti tutorial ini, Anda membutuhkan hal berikut ini:

      Aplikasi kita akan menggunakan setelan pabrik aplikasi Flask dengan cetak biru. Kita akan memiliki satu cetak biru yang menangani segala sesuatu yang terkait dengan auth, dan kita akan memiliki cetak biru lainnya untuk rute reguler kita, yang termasuk indeks dan laman profil terlindungi. Dalam aplikasi sungguhan, Anda dapat mengurai fungsionalitas dengan cara apa pun yang Anda suka, tetapi solusi yang dibahas di sini akan bekerja dengan baik untuk tutorial ini.

      Berikut adalah diagram untuk memberikan gambaran tentang struktur berkas proyek Anda akan terlihat seperti apa setelah Anda menyelesaikan tutorial:

      .
      └── flask_auth_app
          └── project
              ├── __init__.py       # setup our app
              ├── auth.py           # the auth routes for our app
              ├── db.sqlite         # our database
              ├── main.py           # the non-auth routes for our app
              ├── models.py         # our user model
              └── templates
                  ├── base.html     # contains common layout and links
                  ├── index.html    # show the home page
                  ├── login.html    # show the login form
                  ├── profile.html  # show the profile page
                  └── signup.html   # show the signup form
      

      Seiring kita menjalani tutorial ini, kita akan menciptakan direktori dan berkas ini.

      Langkah 1 — Menginstal Paket

      Ada tiga paket utama yang diperlukan untuk proyek kita:

      • Flask
      • Flask-Login: untuk menangani sesi pengguna setelah autentikasi
      • Flask-SQLAlchemy: untuk mewakili antarmuka dan model pengguna dengan basis data kita

      Kita akan menggunakan SQLite untuk menghindari keharusan menginstal dependensi tambahan bagi basis data.

      Pertama-tama, kita akan mulai dengan menciptakan direktori proyek:

      Selanjutnya, kita perlu bernavigasi ke direktori proyek:

      Anda akan ingin menciptakan lingkungan Python jika Anda tidak memilikinya. Tergantung bagaimana Python terinstal pada mesin Anda, perintah Anda akan terlihat mirip seperti ini:

      • python3 -m venv auth
      • source auth/bin/activate

      Catatan: Anda dapat melihat tutorial yang relevan dengan lingkungan lokal untuk menyiapkan venv.

      Jalankan perintah berikut dari lingkungan virtual Anda untuk menginstal paket yang diperlukan:

      • pip install flask flask-sqlalchemy flask-login

      Karena kini Anda telah menginstal paket, Anda siap untuk menciptakan berkas aplikasi utama.

      Langkah 2 — Menciptakan Berkas Aplikasi Utama

      Mari kita mulai dengan menciptakan direktori project:

      Berkas pertama yang akan kita kerjakan adalah berkas __init__.py untuk proyek kita:

      Berkas ini akan memiliki fungsi untuk menciptakan aplikasi kita, yang akan menginisialisasi basis data dan mendaftarkan cetak biru kita. Saat ini, berkas ini tidak terlalu berguna, tetapi akan diperlukan selanjutnya untuk aplikasi kita. Kita perlu menginisialisasi SQLAlchemy, menetapkan beberapa nilai konfigurasi, dan mendaftarkan cetak biru kita di sini.

      project/__init__.py

      from flask import Flask
      from flask_sqlalchemy import SQLAlchemy
      
      # init SQLAlchemy so we can use it later in our models
      db = SQLAlchemy()
      
      def create_app():
          app = Flask(__name__)
      
          app.config['SECRET_KEY'] = 'secret-key-goes-here'
          app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
      
          db.init_app(app)
      
          # blueprint for auth routes in our app
          from .auth import auth as auth_blueprint
          app.register_blueprint(auth_blueprint)
      
          # blueprint for non-auth parts of app
          from .main import main as main_blueprint
          app.register_blueprint(main_blueprint)
      
          return app
      

      Setelah memiliki berkas aplikasi utama, kita dapat mulai menambahkan ke dalam rute kita.

      Langkah 3 — Menambahkan Rute

      Untuk rute, kita akan menggunakan dua cetak biru. Untuk cetak biru utama, kita akan memiliki laman beranda (/) dan laman profil (/profile) untuk setelah kita log masuk. Jika pengguna mencoba mengakses laman profil tanpa log masuk, mereka akan dikirim ke rute log masuk.

      Untuk cetak biru auth, kita akan memiliki rute untuk mengambil baik laman log masuk (/login) dan laman pendaftaran (/sign-up). Kita juga akan memiliki rute untuk menangani permintaan POST dari kedua rute itu. Terakhir, kita akan memiliki rute log keluar (/logout) untuk mengeluarkan pengguna aktif.

      Untuk sementara ini, kita akan mendefinisikan login, signup, dan logout dengan respons sederhana. Kita akan meninjaunya kembali pada langkah selanjutnya dan memperbaruinya dengan fungsionalitas yang diinginkan.

      Pertama-tama, ciptakan main.py untuk main_blueprint:

      project/main.py

      from flask import Blueprint
      from . import db
      
      main = Blueprint('main', __name__)
      
      @main.route('/')
      def index():
          return 'Index'
      
      @main.route('/profile')
      def profile():
          return 'Profile'
      

      Selanjutnya, ciptakan auth.py untuk auth_blueprint:

      project/auth.py

      from flask import Blueprint
      from . import db
      
      auth = Blueprint('auth', __name__)
      
      @auth.route('/login')
      def login():
          return 'Login'
      
      @auth.route('/signup')
      def signup():
          return 'Signup'
      
      @auth.route('/logout')
      def logout():
          return 'Logout'
      

      Di dalam terminal, Anda dapat menetapkan nilai FLASK_APP dan FLASK_DEBUG:

      • export FLASK_APP=project
      • export FLASK_DEBUG=1

      Variabel lingkungan FLASK_APP memberi instruksi pada Flask terkait cara memuat aplikasi. Ini harus mengarah ke tempat create_app berada. Untuk keperluan kita, kita akan mengarahkan ke direktori project.

      Variabel lingkungan FLASK_DEBUG diaktifkan dengan menetapkan nilainya menjadi 1. Ini akan mengaktifkan pengawakutu yang akan menampilkan kesalahan aplikasi di peramban.

      Pastikan Anda berada di direktori flask_auth_app, lalu jalankan proyeknya:

      Sekarang, dalam peramban web, Anda seharusnya dapat bernavigasi ke lima URL yang memungkinkan dan melihat teks yang dihasilkan yang didefinisikan dalam auth.py dan main.py.

      Misalnya, mengunjungi localhost:5000/profile akan menampilkan: Profile:

      Tangkapan layar dari proyek di localhost porta 5000 dalam peramban

      Kini setelah kita memverifikasi bahwa rute berperilaku seperti yang diharapkan, kita dapat melanjutkan ke penciptaan templat.

      Langkah 4 — Menciptakan Templat

      Mari kita lanjutkan dan menciptakan templat yang digunakan dalam aplikasi. Ini adalah langkah pertama sebelum kita dapat menerapkan fungsionalitas log masuk yang sebenarnya. Aplikasi kita akan menggunakan empat templat:

      • index.html
      • profile.html
      • login.html
      • signup.html

      Kita juga akan memiliki templat dasar yang akan memiliki kode umum untuk setiap lamannya. Dalam hal ini, templat dasar akan memiliki tautan navigasi dan tata letak umum dari laman. Mari kita ciptakan sekarang.

      Pertama-tama, ciptakan direktori template di bawah direktori project:

      • mkdir -p project/templates

      Kemudian, ciptakan base.html:

      • nano project/templates/base.html

      Selanjutnya, tambahkan kode berikut ke berkas base.html:

      project/templates/base.html

      <!DOCTYPE html>
      <html>
      
      <head>
          <meta charset="utf-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <title>Flask Auth Example</title>
          <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css" />
      </head>
      
      <body>
          <section class="hero is-primary is-fullheight">
      
              <div class="hero-head">
                  <nav class="navbar">
                      <div class="container">
      
                          <div id="navbarMenuHeroA" class="navbar-menu">
                              <div class="navbar-end">
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.index') }}" class="navbar-item">
                                      Home
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.profile') }}" class="navbar-item">
                                      Profile
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}" class="navbar-item">
                                      Login
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.signup') }}" class="navbar-item">
                                      Sign Up
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.logout') }}" class="navbar-item">
                                      Logout
                                  </a>
                              </div>
                          </div>
                      </div>
                  </nav>
              </div>
      
              <div class="hero-body">
                  <div class="container has-text-centered">
                     {% block content %}
                     {% endblock %}
                  </div>
              </div>
          </section>
      </body>
      
      </html>
      

      Kode ini akan menciptakan serangkaian menu yang terhubung ke setiap laman dari aplikasi dan daerah tempat konten akan muncul.

      Catatan: Di balik layar, kita menggunakan Bulma untuk menangani pengaturan gaya dan tata letak. Untuk pengetahuan yang lebih dalam tentang Bulma, pertimbangkan untuk membaca dokumentasi Bulma resmi.

      Selanjutnya, ciptakan templates/index.html:

      • nano project/templates/index.html

      Tambahkan kode berikut ke berkas yang baru saja diciptakan untuk menambahkan konten ke laman:

      project/templates/index.html

      {% extends "base.html" %}
      
      {% block content %}
      <h1 class="title">
        Flask Login Example
      </h1>
      <h2 class="subtitle">
        Easy authentication and authorization in Flask.
      </h2>
      {% endblock %}
      

      Kode ini akan menciptakan laman indeks dasar dengan judul dan subjudul.

      Selanjutnya, ciptakan templates/login.html:

      • nano project/templates/login.html

      Kode ini menghasilkan laman log masuk dengan bidang untuk Surel dan Kata Sandi. Ada juga kotak centang untuk “mengingat” suatu sesi log masuk.

      project/templates/login.html

      {% extends "base.html" %}
      
      {% block content %}
      <div class="column is-4 is-offset-4">
          <h3 class="title">Login</h3>
          <div class="box">
              <form method="POST" action="/login">
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="email" name="email" placeholder="Your Email" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="password" name="password" placeholder="Your Password">
                      </div>
                  </div>
                  <div class="field">
                      <label class="checkbox">
                          <input type="checkbox">
                          Remember me
                      </label>
                  </div>
                  <button class="button is-block is-info is-large is-fullwidth">Login</button>
              </form>
          </div>
      </div>
      {% endblock %}
      

      Selanjutnya, ciptakan templates/signup.html:

      • nano project/templates/signup.html

      Tambahkan kode berikut untuk menciptakan laman pendaftaran dengan bidang untuk surel, nama, dan kata sandi:

      project/templates/signup.html

      {% extends "base.html" %}
      
      {% block content %}
      <div class="column is-4 is-offset-4">
          <h3 class="title">Sign Up</h3>
          <div class="box">
              <form method="POST" action="/signup">
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="email" name="email" placeholder="Email" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="text" name="name" placeholder="Name" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="password" name="password" placeholder="Password">
                      </div>
                  </div>
      
                  <button class="button is-block is-info is-large is-fullwidth">Sign Up</button>
              </form>
          </div>
      </div>
      {% endblock %}
      

      Selanjutnya, ciptakan templates/profile.html:

      • nano project/templates/profile.html

      Tambahkan kode ini untuk menciptakan laman sederhana dengan judul yang dikodekan secara permanen untuk menyambut Anthony:

      project/templates/profile.html

      {% extends "base.html" %}
      
      {% block content %}
      <h1 class="title">
        Welcome, Anthony!
      </h1>
      {% endblock %}
      

      Nanti, kita akan menambahkan kode untuk menyapa pengguna siapa pun secara dinamis.

      Setelah Anda menambah templat, kita dapat memperbarui pernyataan respons di setiap rute ketika kita harus memberikan templat alih-alih teks.

      Selanjutnya, perbarui main.py dengan memodifikasi baris impor dan rute untuk index dan profile:

      project/main.py

      from flask import Blueprint, render_template
      ...
      @main.route('/')
      def index():
          return render_template('index.html')
      
      @main.route('/profile')
      def profile():
          return render_template('profile.html')
      

      Sekarang Anda akan memperbarui auth.py dengan memodifikasi baris impor dan rute untuk login dan signup:

      project/auth.py

      from flask import Blueprint, render_template
      ...
      @auth.route('/login')
      def login():
          return render_template('login.html')
      
      @auth.route('/signup')
      def signup():
          return render_template('signup.html')
      

      Setelah Anda membuat perubahan ini, laman pendaftaran akan terlihat seperti ini jika Anda bernavigasi ke /sign-up:

      Laman pendaftaran di /signup

      Anda seharusnya dapat melihat laman untuk /, /login, dan /profile juga.

      Kita akan membiarkan /logout untuk saat ini karena /logout tidak akan menampilkan templat saat selesai.

      Langkah 5 — Menciptakan Model Pengguna

      Model pengguna kita mewakili seberapa berartinya memiliki pengguna bagi aplikasi kita. Kita akan memiliki bidang untuk alamat surel, kata sandi, dan nama. Di aplikasi, Anda mungkin memutuskan bahwa Anda menginginkan lebih banyak informasi untuk disimpan per pengguna. Anda dapat menambah hal-hal seperti ulang tahun, foto profil, lokasi, atau preferensi pengguna apa pun.

      Model yang diciptakan dalam Flask-SQLAlchemy diwakili oleh kelas-kelas yang kemudian diterjemahkan ke tabel-tabel di dalam basis data. Atribut dari kelas-kelas itu lalu berubah menjadi kolom-kolom untuk tabel tersebut.

      Mari kita lanjutkan dan ciptakan model pengguna itu:

      Kode ini menciptakan model pengguna dengan kolom untuk id, email, password, dan name:

      project/models.py

      from . import db
      
      class User(db.Model):
          id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

      Karena kini Anda telah menciptakan model pengguna, Anda dapat melanjutkan ke mengonfigurasi basis data.

      Langkah 6 — Mengonfigurasi Basis Data

      Seperti yang tercantum di dalam Prasyarat, kita akan menggunakan basis data SQLite. Kita dapat menciptakan basis data SQLite sendiri, tetapi mari kita biarkan Flask-SQLAlchemy yang melakukannya untuk kita. Kita telah memiliki jalur basis data yang ditentukan dalam berkas __init__.py, sehingga kita hanya perlu memberi tahu Flask-SQLAlchemy untuk menciptakan basis data di Python REPL.

      Jika Anda menghentikan aplikasi dan membuka Python REPL, kita dapat menciptakan basis data menggunakan metode create_all pada objek db. Pastikan Anda masih berada di lingkungan virtual dan di dalam direktori >flask_auth_app.

      • from project import db, create_app
      • db.create_all(app=create_app()) # pass the create_app result so Flask-SQLAlchemy gets the configuration.

      Catatan: Jika menggunakan penafsir Python merupakan hal baru bagi Anda, Anda dapat melihat dokumentasi resmi.

      Sekarang Anda akan melihat berkas db.sqlite di dalam direktori proyek. Basis data ini akan memiliki tabel pengguna kita di dalamnya.

      Langkah 7 — Menyiapkan Fungsi Otorisasi

      Untuk fungsi pendaftaran, kita akan mengambil data yang diketik pengguna ke dalam formulir dan menambahkannya ke dalam basis data kita. Sebelum menambahkannya, kita perlu memastikan bahwa pengguna tidak ada di basis data. Jika pengguna tidak ada, kita perlu memastikan kita melakukan hash kata sandi sebelum menempatkannya ke dalam basis data karena kita tidak mau kata sandi kita disimpan dalam teks polos.

      Mari kita mulai dengan menambahkan fungsi kedua untuk menangani data formulir POST. Dalam fungsi ini, kita akan mengumpulkan data yang diwariskan dari pengguna terlebih dahulu.

      Ciptakan fungsi dan tambahkan pengalihan di bagian bawah. Perintah ini akan memberikan pengalaman pengguna dari pendaftaran yang berhasil dan diarahkan ke Laman Log Masuk.

      Perbarui auth.py dengan memodifikasi baris impor dan menerapkan signup_post:

      project/auth.py

      from flask import Blueprint, render_template, redirect, url_for
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          # code to validate and add user to database goes here
          return redirect(url_for('auth.login'))
      

      Sekarang, mari kita tambahkan sisa kode yang diperlukan untuk mendaftarkan pengguna.

      Untuk memulai, kita harus menggunakan objek yang diminta untuk mendapatkan data formulir.

      Lanjutkan untuk memperbarui auth.py dengan menambahkan impor dan menerapkan signup_post:

      auth.py

      from flask import Blueprint, render_template, redirect, url_for, request
      from werkzeug.security import generate_password_hash, check_password_hash
      from .models import User
      from . import db
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          email = request.form.get('email')
          name = request.form.get('name')
          password = request.form.get('password')
      
          user = User.query.filter_by(email=email).first() # if this returns a user, then the email already exists in database
      
          if user: # if a user is found, we want to redirect back to signup page so user can try again
              return redirect(url_for('auth.signup'))
      
          # create a new user with the form data. Hash the password so the plaintext version isn't saved.
          new_user = User(email=email, name=name, password=generate_password_hash(password, method='sha256'))
      
          # add the new user to the database
          db.session.add(new_user)
          db.session.commit()
      
          return redirect(url_for('auth.login'))
      

      Catatan: Menyimpan kata sandi dalam teks polos adalah praktik keamanan yang buruk. Anda umumnya akan ingin memanfaatkan algoritma hash yang kompleks dan suatu garam kata sandi agar kata sandi tetap aman.

      Langkah 8 — Menguji Metode Pendaftaran

      Karena kini kita telah menyelesaikan metode pendaftaran, kita seharusnya dapat menciptakan pengguna baru. Gunakan formulir untuk menciptakan pengguna.

      Ada dua cara untuk memverifikasi jika pendaftaran berhasil: Anda dapat menggunakan penampil basis data untuk melihat baris yang ditambahkan ke tabel, atau Anda dapat mencoba mendaftar dengan alamat surel yang sama lagi, dan jika Anda mendapat pesan kesalahan, Anda tahu bahwa surel pertama telah disimpan dengan benar. Mari kita coba pendekatan itu.

      Kita dapat menambahkan kode untuk menginformasikan pengguna bahwa surel sudah ada dan memberi tahu mereka untuk pergi ke laman log masuk. Dengan memanggil fungsi flash, kita akan mengirim pesan ke permintaan selanjutnya, yang dalam hal ini adalah pengalihan. Laman yang kita kunjungi akan memiliki akses ke pesan itu di dalam templat.

      Pertama-tama, kita tambahkan flash sebelum kita mengalihkan kembali ke laman pendaftaran.

      project/auth.py

      from flask import Blueprint, render_template, redirect, url_for, request, flash
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          ...
          if user: # if a user is found, we want to redirect back to signup page so user can try again
              flash('Email address already exists')
              return redirect(url_for('auth.signup'))
      

      Untuk mendapatkan pesan flash di dalam templat, kita dapat menambahkan kode ini di atas formulir. Ini akan menampilkan pesan secara langsung di atas formulir.

      project/templates/signup.html

      ...
      {% with messages = get_flashed_messages() %}
      {% if messages %}
          <div class="notification is-danger">
              {{ messages[0] }}. Go to <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}">login page</a>.
          </div>
      {% endif %}
      {% endwith %}
      <form method="POST" action="/signup">
      

      Kotak pendaftaran menampilkan pesan

      Langkah 9 — Menambahkan Metode Log Masuk

      Metode log masuk mirip dengan fungsi pendaftaran dalam hal kita akan mengambil informasi pengguna dan melakukan sesuatu dengannya. Dalam kasus ini, kita akan membandingkan alamat surel yang dimasukkan untuk melihat apakah alamat itu ada di dalam basis data. Jika demikian, kita akan menguji kata sandi yang disediakan pengguna dengan melakukan hash kata sandi yang diberikan pengguna dan membandingkannya dengan kata sandi yang telah melalui proses hash yang ada di dalam basis data. Kita tahu pengguna telah memasukkan kata sandi yang benar saat kedua kata sandi yang telah melalui proses hash sesuai.

      Setelah pengguna melewati pemeriksaan kata sandi, kita tahu bahwa pengguna itu memiliki kredensial yang benar dan kita dapat membuat mereka log masuk menggunakan Flask-Login. Dengan memanggil login_user, Flask-Login akan menciptakan sesi untuk pengguna tersebut yang akan tetap aktif selama pengguna tetap log masuk, yang akan memungkinkan pengguna untuk melihat laman terlindungi.

      Kita dapat memulai dengan rute baru untuk menangani data POSTed. Kita akan mengalihkan ke laman profil saat pengguna berhasil log masuk:

      project/auth.py

      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          # login code goes here
          return redirect(url_for('main.profile'))
      

      Sekarang, kita perlu memverifikasi apakah pengguna memiliki kredensial yang benar:

      project/auth.py

      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          email = request.form.get('email')
          password = request.form.get('password')
          remember = True if request.form.get('remember') else False
      
          user = User.query.filter_by(email=email).first()
      
          # check if the user actually exists
          # take the user-supplied password, hash it, and compare it to the hashed password in the database
          if not user or not check_password_hash(user.password, password):
              flash('Please check your login details and try again.')
              return redirect(url_for('auth.login')) # if the user doesn't exist or password is wrong, reload the page
      
          # if the above check passes, then we know the user has the right credentials
          return redirect(url_for('main.profile'))
      

      Mari kita tambahkan blok ke dalam templat sehingga pengguna dapat melihat pesan flash. Seperti formulir pendaftaran, mari kita tambahkan pesan kesalahan potensial secara langsung di atas formulir:

      project/templates/login.html

      ...
      {% with messages = get_flashed_messages() %}
      {% if messages %}
          <div class="notification is-danger">
              {{ messages[0] }}
          </div>
      {% endif %}
      {% endwith %}
      <form method="POST" action="/login">
      

      Kini kita telah memiliki kemampuan untuk mengatakan pengguna telah berhasil log masuk, tetapi pengguna tidak masuk ke mana pun. Ini adalah saat kita menggunakan Flask-Login untuk mengelola sesi pengguna.

      Sebelum kita memulai, kita memerlukan beberapa hal agar Flask-Login bekerja. Mulai dengan menambahkan UserMixin ke model Pengguna Anda. UserMixin akan menambahkan atribut Flask-Login ke model sehingga Flask-Login akan dapat bekerja dengannya.

      models.py

      from flask_login import UserMixin
      from . import db
      
      class User(UserMixin, db.Model):
          id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

      Kemudian, kita perlu menentukan pemuat pengguna kita. Pemuat pengguna memberi tahu Flask-Login cara menemukan pengguna tertentu dari ID yang disimpan di dalam kuki sesi mereka. Kita dapat menambahkan ini ke dalam fungsi create_app bersama dengan kode init untuk Flask-Login:

      project/__init__.py

      ...
      from flask_login import LoginManager
      ...
      def create_app():
          ...
          db.init_app(app)
      
          login_manager = LoginManager()
          login_manager.login_view = 'auth.login'
          login_manager.init_app(app)
      
          from .models import User
      
          @login_manager.user_loader
          def load_user(user_id):
              # since the user_id is just the primary key of our user table, use it in the query for the user
              return User.query.get(int(user_id))
      

      Terakhir, kita dapat menambahkan fungsi login_user sebelum kita mengalihkan ke laman profil untuk menciptakan sesi:

      project/auth.py

      from flask_login import login_user
      from .models import User
      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          ...
          # if the above check passes, then we know the user has the right credentials
          login_user(user, remember=remember)
          return redirect(url_for('main.profile'))
      

      Dengan penyiapan Flask-Login, kita dapat menggunakan rute /login. Ketika semuanya disiapkan dengan benar, Anda akan melihat laman profil.

      Laman profil dengan

      Langkah 10 — Melindungi Laman

      Jika nama Anda bukan Anthony, Anda akan melihat bahwa nama Anda salah. Kita ingin profil menampilkan nama yang ada di dalam basis data. Pertama-tama, kita perlu melindungi laman itu, kemudian mengakses data pengguna untuk mendapatkan namanya.

      Untuk melindungi laman saat menggunakan Flask-Login, kita menambahkan dekorator @login_required antara rute dan fungsi. Ini akan mencegah pengguna yang tidak log masuk untuk melihat rute. Jika pengguna tidak log masuk, pengguna akan dialihkan ke laman log masuk, sesuai konfigurasi Flask-Login.

      Dengan rute yang dilengkapi oleh dekorator @login_required, kita akan memiliki kemampuan untuk menggunakan objek current_user di dalam fungsi. current_user ini mewakili pengguna dari basis data, dan kita dapat mengakses semua atribut pengguna itu dengan notasi titik. Misalnya, current_user.email, current_user.password, dan current_user.name, serta current_user.id akan memberikan nilai sebenarnya yang disimpan di dalam basis data bagi pengguna yang log masuk.

      Mari kita gunakan nama pengguna saat ini dan mengirimkannya ke templat. Kemudian, kita akan menggunakan nama itu dan menampilkan nilainya.

      project/main.py

      from flask_login import login_required, current_user
      ...
      @main.route('/profile')
      @login_required
      def profile():
          return render_template('profile.html', name=current_user.name)
      

      Lalu, dalam berkas profile.html, perbarui laman untuk menampilkan nilai name:

      project/templates/profile.html

      ...
      <h1 class="title">
        Welcome, {{ name }}!
      </h1>
      

      Setelah kita mengunjungi laman profil, kita akan melihat bahwa nama pengguna muncul.

      Laman sambutan pengguna dengan nama pengguna yang sedang log masuk saat ini

      Hal terakhir yang dapat kita lakukan adalah memperbarui tampilan log keluar. Kita dapat memanggil fungsi logout_user dalam suatu rute untuk log keluar. Kita memiliki dekorator @login_required karena tidak masuk akal untuk mengeluarkan pengguna yang sebelumnya tidak log masuk.

      project/auth.py

      from flask_login import login_user, logout_user, login_required
      ...
      @auth.route('/logout')
      @login_required
      def logout():
          logout_user()
          return redirect(url_for('main.index'))
      

      Setelah kita log keluar dan mencoba melihat laman profil lagi, kita melihat pesan kesalahan muncul. Ini karena Flask-Login melakukan flash pesan untuk kita ketika pengguna tidak diizinkan untuk mengakses laman.

      Laman log masuk dengan pesan menunjukkan bahwa pengguna harus log masuk untuk mengakses laman

      Satu hal terakhir yang dapat kita lakukan adalah memasukkan pernyataan if di dalam templat untuk menampilkan hanya tautan yang relevan dengan pengguna. Jadi, sebelum pengguna log masuk, mereka akan memiliki opsi untuk log masuk atau mendaftar. Setelah mereka log masuk, mereka dapat mengunjungi profil mereka atau log keluar:

      templates/base.html

      ...
      <div class="navbar-end">
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.index') }}" class="navbar-item">
              Home
          </a>
          {% if current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.profile') }}" class="navbar-item">
              Profile
          </a>
          {% endif %}
          {% if not current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}" class="navbar-item">
              Login
          </a>
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.signup') }}" class="navbar-item">
              Sign Up
          </a>
          {% endif %}
          {% if current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.logout') }}" class="navbar-item">
              Logout
          </a>
          {% endif %}
      </div>
      

      Laman beranda dengan navigasi Home, Login, dan Sign Up di bagian atas layar

      Dengan demikian, Anda telah berhasil membangun aplikasi Anda dengan autentikasi.

      Kesimpulan

      Kita telah menggunakan Flask-Login dan Flask-SQLAlchemy untuk membangun sistem log masuk pada aplikasi. Kita telah membahas cara melakukan autentikasi pengguna dengan menciptakan model pengguna dan menyimpan informasi pengguna terlebih dahulu. Kemudian, kita harus memverifikasi bahwa kata sandi pengguna adalah benar dengan melakukan hash kata sandi dari formulir dan membandingkannya dengan yang disimpan di basis data. Terakhir, kita menambahkan otorisasi ke aplikasi kita menggunakan dekorator @login_required di laman profil sehingga hanya pengguna yang sedang log masuk yang dapat melihat laman itu.

      Yang kita ciptakan dalam tutorial ini akan cukup untuk aplikasi yang kecil, tetapi jika Anda ingin memiliki fungsionalitas lebih banyak sejak awal, Anda mungkin dapat mempertimbangkan untuk menggunakan baik pustaka Flask-User atau Flask-Security, yang mana keduanya dibangun di atas pustaka Flask-Login.



      Source link

      Cómo añadir autenticación a su aplicación con Flask-Login


      Introducción

      Permitir a los usuarios iniciar sesión en su aplicación es una de las funciones más frecuentes que añadirá a su aplicación web. Este artículo explicará cómo añadir autenticación a su aplicación Flask con el paquete Flask-Login.

      Gif animado de la aplicación Flask y cuadro de inicio de sesión

      Crearemos algunas páginas de registro e inicio de sesión que permiten a los usuarios iniciar sesión y acceder a páginas protegidas que los usuarios que no hayan iniciado sesión no pueden ver. Obtendremos información del modelo de usuario y la mostraremos en nuestras páginas protegidas cuando el usuario inicie sesión para simular el aspecto que tendrá un perfil.

      En este artículo, explicaremos lo siguiente:

      • Usar la biblioteca de Flask-Login para la administración de las sesiones
      • Usar la utilidad Flask integrada para autenticar contraseñas
      • Añadir páginas protegidas a nuestra aplicación solo para los usuarios con sesión iniciada
      • Usar Flask-SQLAlchemy para crear un modelo de usuario
      • Crear formularios de registro e inicio de sesión para que nuestros usuarios creen cuentas e inicien sesión
      • Devolver mensajes intermitentes de error a los usuarios cuando algo falle
      • Usar la información de la cuenta del usuario para mostrarla en la página de perfil

      El código fuente para este proyecto está disponible en GitHub.

      Requisitos previos

      Para completar este tutorial, necesitará lo siguiente:

      Nuestra aplicación usará el patrón de fábrica de aplicación Flask con modelos. Tendremos un modelo para gestionar todo lo relacionado con la autenticación, y otro para nuestras rutas regulares, que incluyen el índice y la página de perfil protegida. En una aplicación real, puede desglosar la funcionalidad de cualquier forma que quiera, pero la solución explicada aquí funcionará bien para este tutorial.

      Aquí, tiene un diagrama que muestra cómo se verá la estructura de archivos de su proyecto una vez que haya completado el tutorial:

      .
      └── flask_auth_app
          └── project
              ├── __init__.py       # setup our app
              ├── auth.py           # the auth routes for our app
              ├── db.sqlite         # our database
              ├── main.py           # the non-auth routes for our app
              ├── models.py         # our user model
              └── templates
                  ├── base.html     # contains common layout and links
                  ├── index.html    # show the home page
                  ├── login.html    # show the login form
                  ├── profile.html  # show the profile page
                  └── signup.html   # show the signup form
      

      A medida que avancemos en el tutorial, crearemos estos directorios y archivos.

      Paso 1: Instalar paquetes

      Estos son los tres paquetes principales que necesitamos para nuestro proyecto:

      • Flask
      • Flask-Login: para administrar las sesiones del usuario tras la autenticación
      • Flask-SQLAlchemy: para representar el modelo de usuario y la interfaz con nuestra base de datos

      Usaremos SQLite para evitar tener que instalar dependencias adicionales para la base de datos.

      Primero, empezaremos por crear el directorio del proyecto:

      A continuación, debemos navegar al directorio del proyecto:

      Querrá crear un entorno Python si no tiene uno. Dependiendo de cómo se instaló Python en su equipo, sus comandos tendrán un aspecto similar a:

      • python3 -m venv auth
      • source auth/bin/activate

      Nota: Puede consultar el tutorial relevante a su entorno local para configurar venv.

      Ejecute los siguientes comandos desde su entorno virtual para instalar los paquetes necesarios:

      • pip install flask flask-sqlalchemy flask-login

      Ahora que instaló los paquetes, está listo para crear el principal archivo de la aplicación.

      Paso 2: Crear el archivo principal de la aplicación

      Empezaremos creando un directorio project:

      El primer archivo en el que trabajaremos será el archivo __init__.py para nuestro proyecto:

      Este archivo tendrá la función de crear nuestra aplicación, que iniciará la base de datos y registrará nuestros modelos. En este momento, esto no hará mucho, pero será necesario para el resto de nuestra aplicación. Debemos iniciar SQLAlchemy, establecer algunos valores de configuración y registrar nuestros modelos aquí.

      project/__init__.py

      from flask import Flask
      from flask_sqlalchemy import SQLAlchemy
      
      # init SQLAlchemy so we can use it later in our models
      db = SQLAlchemy()
      
      def create_app():
          app = Flask(__name__)
      
          app.config['SECRET_KEY'] = 'secret-key-goes-here'
          app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
      
          db.init_app(app)
      
          # blueprint for auth routes in our app
          from .auth import auth as auth_blueprint
          app.register_blueprint(auth_blueprint)
      
          # blueprint for non-auth parts of app
          from .main import main as main_blueprint
          app.register_blueprint(main_blueprint)
      
          return app
      

      Ahora que tenemos el archivo principal de la aplicación, podemos comenzar a añadir nuestras rutas.

      Paso 3: Añadir rutas

      Para nuestras rutas, usaremos dos modelos. Para nuestro modelo principal, tendremos una página principal (/) y una página de perfil (/profile) para cuando iniciemos sesión. Si el usuario intenta acceder a la página de perfil sin iniciar sesión, se lo enviará a la ruta de inicio de sesión.

      Para nuestro modelo de autenticación, tendremos rutas para recuperar la página de inicio de sesión (/login) y la página de registro (/sign-up). También tendremos rutas para gestionar las solicitudes POST desde ambas rutas. Finalmente, tendremos una ruta para cerrar sesión (/logout) para cerrar la sesión de un usuario activo.

      Por el momento, definiremos login, signup y logout con retornos simples. Los repasaremos más adelante y los actualizaremos con la funcionalidad deseada.

      Primero, cree main.py para su main_blueprint:

      project/main.py

      from flask import Blueprint
      from . import db
      
      main = Blueprint('main', __name__)
      
      @main.route('/')
      def index():
          return 'Index'
      
      @main.route('/profile')
      def profile():
          return 'Profile'
      

      A continuación, cree auth.py para su auth_blueprint:

      project/auth.py

      from flask import Blueprint
      from . import db
      
      auth = Blueprint('auth', __name__)
      
      @auth.route('/login')
      def login():
          return 'Login'
      
      @auth.route('/signup')
      def signup():
          return 'Signup'
      
      @auth.route('/logout')
      def logout():
          return 'Logout'
      

      En un terminal, puede configurar los valores FLASK_APP y FLASK_DEBUG:

      • export FLASK_APP=project
      • export FLASK_DEBUG=1

      La variable de entorno FLASK_APP indica a Flask cómo cargar la aplicación. Debería apuntar hacia donde está create_app. Para nuestros fines, apuntaremos al directorio project.

      La variable de entorno FLASK_DEBUG se habilita configurándola en 1. Esto habilitará un depurador que mostrará los errores de la aplicación en el navegador.

      Asegúrese de que está en el directorio flask_auth_app y, a continuación, ejecute el proyecto:

      Ahora, en un navegador web, debería poder navegar a las cinco URL posibles y ver el texto devuelto que se definió en auth.py y main.py.

      Por ejemplo, visitar localhost:5000/profile muestra: Profile:

      Captura de pantalla del proyecto en el puerto localhost 5000 en el navegador

      Ahora que ya verificamos que nuestras rutas se comportan como se espera, podemos crear las plantillas.

      Paso 4: Crear plantillas

      Ahora crearemos las plantillas usadas en nuestra aplicación. Este es el primer paso antes de poder implementar la funcionalidad real de inicio de sesión. Nuestra aplicación usará cuatro plantillas:

      • index.html
      • profile.html
      • login.html
      • signup.html

      También tendremos una plantilla base que tendrá un código común para cada una de las páginas. En este caso, la plantilla base tendrá enlaces de navegación y el diseño general de la página. Vamos a crearlas ahora.

      Primero, cree un directorio templates en el directorio project:

      • mkdir -p project/templates

      A continuación, cree base.html:

      • nano project/templates/base.html

      A continuación, añada el siguiente código al archivo base.html:

      project/templates/base.html

      <!DOCTYPE html>
      <html>
      
      <head>
          <meta charset="utf-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <title>Flask Auth Example</title>
          <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css" />
      </head>
      
      <body>
          <section class="hero is-primary is-fullheight">
      
              <div class="hero-head">
                  <nav class="navbar">
                      <div class="container">
      
                          <div id="navbarMenuHeroA" class="navbar-menu">
                              <div class="navbar-end">
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.index') }}" class="navbar-item">
                                      Home
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.profile') }}" class="navbar-item">
                                      Profile
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}" class="navbar-item">
                                      Login
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.signup') }}" class="navbar-item">
                                      Sign Up
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.logout') }}" class="navbar-item">
                                      Logout
                                  </a>
                              </div>
                          </div>
                      </div>
                  </nav>
              </div>
      
              <div class="hero-body">
                  <div class="container has-text-centered">
                     {% block content %}
                     {% endblock %}
                  </div>
              </div>
          </section>
      </body>
      
      </html>
      

      Este código creará una serie de enlaces de menú a cada página de la aplicación y un área donde aparecerá el contenido.

      Nota: En segundo plano, estamos usando Bulma para gestionar el estilo y la distribución. Para aprender más sobre Bluma, considere leer la documentación oficial de Bulma.

      A continuación, cree templates/index.html:

      • nano project/templates/index.html

      Añada el siguiente código al archivo recién creado para añadir contenido a la página:

      project/templates/index.html

      {% extends "base.html" %}
      
      {% block content %}
      <h1 class="title">
        Flask Login Example
      </h1>
      <h2 class="subtitle">
        Easy authentication and authorization in Flask.
      </h2>
      {% endblock %}
      

      Este código creará una página de índice básica con un título y un subtítulo.

      A continuación, cree templates/login.html:

      • nano project/templates/login.html

      Este código genera una página de inicio con campos para Correo electrónico y Contraseña. También hay una casilla de verificación para “recordar” una sesión iniciada.

      project/templates/login.html

      {% extends "base.html" %}
      
      {% block content %}
      <div class="column is-4 is-offset-4">
          <h3 class="title">Login</h3>
          <div class="box">
              <form method="POST" action="/login">
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="email" name="email" placeholder="Your Email" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="password" name="password" placeholder="Your Password">
                      </div>
                  </div>
                  <div class="field">
                      <label class="checkbox">
                          <input type="checkbox">
                          Remember me
                      </label>
                  </div>
                  <button class="button is-block is-info is-large is-fullwidth">Login</button>
              </form>
          </div>
      </div>
      {% endblock %}
      

      A continuación, cree templates/signup.html:

      • nano project/templates/signup.html

      Añada el siguiente código para crear una página de registro con campos para correo electrónico, nombre y contraseña:

      project/templates/signup.html

      {% extends "base.html" %}
      
      {% block content %}
      <div class="column is-4 is-offset-4">
          <h3 class="title">Sign Up</h3>
          <div class="box">
              <form method="POST" action="/signup">
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="email" name="email" placeholder="Email" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="text" name="name" placeholder="Name" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="password" name="password" placeholder="Password">
                      </div>
                  </div>
      
                  <button class="button is-block is-info is-large is-fullwidth">Sign Up</button>
              </form>
          </div>
      </div>
      {% endblock %}
      

      A continuación, cree templates/profile.html:

      • nano project/templates/profile.html

      Añada este código para crear una página sencilla con un título codificado de forma rígida para darle la bienvenida a Anthony:

      project/templates/profile.html

      {% extends "base.html" %}
      
      {% block content %}
      <h1 class="title">
        Welcome, Anthony!
      </h1>
      {% endblock %}
      

      Más adelante, añadiremos un código para saludar dinámicamente a cualquier usuario.

      Una vez que haya añadido las plantillas, podremos actualizar las instrucciones de retorno en cada una de las rutas que tenemos para que devuelvan las plantillas en vez del texto.

      A continuación, actualice main.py modificando la línea de importación y las rutas para index y profile:

      project/main.py

      from flask import Blueprint, render_template
      ...
      @main.route('/')
      def index():
          return render_template('index.html')
      
      @main.route('/profile')
      def profile():
          return render_template('profile.html')
      

      Ahora, actualizará auth.py modificando la línea de importación y las rutas para login y signup:

      project/auth.py

      from flask import Blueprint, render_template
      ...
      @auth.route('/login')
      def login():
          return render_template('login.html')
      
      @auth.route('/signup')
      def signup():
          return render_template('signup.html')
      

      Una vez que haya realizado estos cambios, así lucirá la página de registro si navega a /sign-up:

      Página de registro en /signup

      También debería poder ver las páginas para /, /login y /profile.

      No trabajaremos con /logout por ahora porque no mostrará una plantilla cuando esté listo.

      Paso 5: Crear modelos de usuario

      Nuestro modelo de usuario representa qué significa para nuestra aplicación tener un usuario. Tendremos campos para una dirección de correo electrónico, contraseña y nombre. En su aplicación, puede decidir que quiere guardar mucha más información por usuario. Puede añadir cosas como fecha de nacimiento, perfil, imagen, ubicación o cualquier preferencia del usuario.

      Los modelos creados en Flask-SQLAlchemy se representan mediante clases y, luego, se trasladan a tablas en una base de datos. Los atributos de esas clases se convierten en columnas para esas tablas.

      Ahora crearemos ese modelo de usuario:

      Este código crea un modelo de usuario con columnas para id, email, password y name:

      project/models.py

      from . import db
      
      class User(db.Model):
          id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

      Ahora que creó un modelo de usuario, puede configurar su base de datos.

      Paso 6: Configurar la base de datos

      Como se indicó en los requisitos previos, usaremos una base de datos SQLite. Podríamos crear una base de datos SQLite por nuestra cuenta, pero dejemos que Flask-SQLAlchemy lo haga por nosotros. Ya tenemos la ruta de la base de datos especificada en el archivo __init__.py, así que solo necesitamos indicar a Flask-SQLAlchemy que cree la base de datos en el REPL de Python.

      Si detiene su aplicación y abre un REPL de Python, podemos crear la base de datos usando el método create_all en el objeto db. Asegúrese de que aún está en el entorno virtual y en el directorio flask_auth_app.

      • from project import db, create_app
      • db.create_all(app=create_app()) # pass the create_app result so Flask-SQLAlchemy gets the configuration.

      Nota: Si el uso del intérprete de Python es nuevo para usted, puede consultar la documentación oficial.

      Ahora, verá un archivo db.sqlite en el directorio de su proyecto. Esta base de datos contendrá nuestra tabla de usuario.

      Paso 7: Configurar la función de autorización

      Para nuestra función de registro, tomaremos los datos que escriba el usuario en el formulario y los añadiremos a nuestra base de datos. Antes de añadirlo, debemos asegurarnos de que el usuario no existe ya en la base de datos. Si no es así, debemos asegurarnos de autenticar la contraseña antes de colocarla en la base de datos, porque no queremos que nuestras contraseñas se almacenen en archivo de texto.

      Empezaremos por añadir una segunda función para gestionar los datos del formulario POST. En esta función, recopilaremos primero los datos ingresados por el usuario.

      Cree la función y añada una redirección en la parte inferior. Esto proporcionará una experiencia de usuario de un registro correcto y se lo redirigirá a la página de inicio de sesión.

      Actualice auth.py modificando la línea de importación e implementando signup_post:

      project/auth.py

      from flask import Blueprint, render_template, redirect, url_for
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          # code to validate and add user to database goes here
          return redirect(url_for('auth.login'))
      

      Ahora, añadiremos el resto del código necesario para registrar a un usuario.

      Para comenzar, tendremos que usar el objeto de solicitud para obtener los datos del formulario.

      Continúe para actualizar auth.py añadiendo importaciones e implementando signup_post:

      auth.py

      from flask import Blueprint, render_template, redirect, url_for, request
      from werkzeug.security import generate_password_hash, check_password_hash
      from .models import User
      from . import db
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          email = request.form.get('email')
          name = request.form.get('name')
          password = request.form.get('password')
      
          user = User.query.filter_by(email=email).first() # if this returns a user, then the email already exists in database
      
          if user: # if a user is found, we want to redirect back to signup page so user can try again
              return redirect(url_for('auth.signup'))
      
          # create a new user with the form data. Hash the password so the plaintext version isn't saved.
          new_user = User(email=email, name=name, password=generate_password_hash(password, method='sha256'))
      
          # add the new user to the database
          db.session.add(new_user)
          db.session.commit()
      
          return redirect(url_for('auth.login'))
      

      Nota: El almacenamiento de contraseñas en archivos de texto se considera una mala práctica de seguridad. Normalmente, querrá usar un algoritmo de autenticación complejo y una sal de contraseña para proteger las contraseñas.

      Paso 8: Probar el método de registro

      Ahora que tenemos el método de registro, deberíamos poder crear un nuevo usuario. Use el formulario para crear un usuario.

      Hay dos formas de verificar si el registro funcionó: puede usar un visor de base de datos para ver la fila que se añadió a su tabla o puede intentar registrarse con la misma dirección de correo de nuevo y, si recibe un error, sabe que el primer correo electrónico se guardó correctamente. Hagamos eso.

      Podemos añadir un código para permitir al usuario saber que el correo electrónico ya existe e indicarle que vaya a la página de inicio de sesión. Al invocar la función flash, enviaremos un mensaje a la siguiente solicitud que, en este caso, es la redirección. La página a la que llegamos tendrá acceso a ese mensaje en la plantilla.

      Primero, añadimos flash antes de redirigir a nuestra página de registro.

      project/auth.py

      from flask import Blueprint, render_template, redirect, url_for, request, flash
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          ...
          if user: # if a user is found, we want to redirect back to signup page so user can try again
              flash('Email address already exists')
              return redirect(url_for('auth.signup'))
      

      Para obtener el mensaje intermitente en la plantilla, podemos añadir este código sobre el formulario. Esto mostrará el mensaje directamente arriba del formulario.

      project/templates/signup.html

      ...
      {% with messages = get_flashed_messages() %}
      {% if messages %}
          <div class="notification is-danger">
              {{ messages[0] }}. Go to <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}">login page</a>.
          </div>
      {% endif %}
      {% endwith %}
      <form method="POST" action="/signup">
      

      Cuadro de registro mostrando el mensaje

      Paso 9: Añadir el método de inicio de sesión

      El método de inicio de sesión es similar a la función de registro porque tomaremos la información del usuario y haremos algo con ella. En este caso, compararemos la dirección de correo electrónico introducida para ver si está en la base de datos. Si es así, probaremos la contraseña proporcionada por el usuario autenticando la contraseña que el usuario introduce y comparándola con la contraseña autenticada en la base de datos. Sabemos que el usuario introdujo la contraseña correcta cuando ambas contraseñas autenticadas coinciden.

      Una vez que el usuario haya pasado la comprobación de contraseña, sabemos que tiene las credenciales correctas y puede iniciar sesión usando Flask-Login. Al invocar login_user, Flask-Login creará una sesión para ese usuario que persistirá mientras el usuario permanezca con sesión iniciada, lo que permitirá al usuario ver las páginas protegidas.

      Podemos comenzar con una nueva ruta para gestionar los datos que ya fueron procesados por POST. Redirigiremos a la página de perfil cuando el usuario inicie sesión correctamente.

      project/auth.py

      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          # login code goes here
          return redirect(url_for('main.profile'))
      

      Ahora, debemos verificar si el usuario tiene las credenciales correctas:

      project/auth.py

      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          email = request.form.get('email')
          password = request.form.get('password')
          remember = True if request.form.get('remember') else False
      
          user = User.query.filter_by(email=email).first()
      
          # check if the user actually exists
          # take the user-supplied password, hash it, and compare it to the hashed password in the database
          if not user or not check_password_hash(user.password, password):
              flash('Please check your login details and try again.')
              return redirect(url_for('auth.login')) # if the user doesn't exist or password is wrong, reload the page
      
          # if the above check passes, then we know the user has the right credentials
          return redirect(url_for('main.profile'))
      

      Añadiremos el bloque en la plantilla para que el usuario pueda ver el mensaje intermitente. Al igual que con el formulario de registro, añadiremos el potencial mensaje de error directamente arriba del formulario:

      project/templates/login.html

      ...
      {% with messages = get_flashed_messages() %}
      {% if messages %}
          <div class="notification is-danger">
              {{ messages[0] }}
          </div>
      {% endif %}
      {% endwith %}
      <form method="POST" action="/login">
      

      Ahora podemos decir que un usuario inició sesión correctamente, pero no tenemos nada para registrar la información del usuario. Aquí es donde traemos a Flask-Login para gestionar las sesiones de usuario.

      Antes de comenzar, necesitamos algunas cosas para que Flask-Login funcione. Comience añadiendo UserMixin a su modelo de usuario. El UserMixin añadirá atributos de Flask-Login al modelo de forma que Flask-Login pueda trabajar con él.

      models.py

      from flask_login import UserMixin
      from . import db
      
      class User(UserMixin, db.Model):
          id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

      A continuación, necesitamos especificar nuestro cargador de usuario. Un cargador de usuario indica a Flask-Login cómo encontrar un usuario específico a partir del identificador que se almacena en su cookie de sesión. Podemos añadir esto en nuestra función create_app junto con el código init para Flask-Login:

      project/__init__.py

      ...
      from flask_login import LoginManager
      ...
      def create_app():
          ...
          db.init_app(app)
      
          login_manager = LoginManager()
          login_manager.login_view = 'auth.login'
          login_manager.init_app(app)
      
          from .models import User
      
          @login_manager.user_loader
          def load_user(user_id):
              # since the user_id is just the primary key of our user table, use it in the query for the user
              return User.query.get(int(user_id))
      

      Finalmente, podemos añadir la función login_user justo antes de redirigir a la página de perfil para crear la sesión:

      project/auth.py

      from flask_login import login_user
      from .models import User
      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          ...
          # if the above check passes, then we know the user has the right credentials
          login_user(user, remember=remember)
          return redirect(url_for('main.profile'))
      

      Con la configuración de Flask-Login, podemos usar la ruta /login. Cuando todo esté listo, verá la página de perfil.

      Página de perfil con

      Paso 10: Proteger las páginas

      Si su nombre no es Anthony, verá que el nombre está mal. Lo que queremos es que el perfil muestre el nombre en la base de datos. Primero debemos proteger la página y, luego, acceder a los datos del usuario para obtener el nombre.

      Para proteger una página cuando se usa Flask-Login, añadiremos el decorador @login_required entre la ruta y la función. Esto evitará que un usuario que no haya iniciado sesión vea la ruta. Si el usuario no inició sesión, se lo redirigirá a la página de inicio, según la configuración de Flask-Login.

      Con las rutas representadas con el decorador @login_required, tenemos la capacidad de usar el objeto current_user dentro de la función. Este current_user representa al usuario de la base de datos, y podemos acceder a todos los atributos de ese usuario con notación por puntos. Por ejemplo, current_user.email, current_user.password y current_user.name y current_user.id devolverán los valores reales almacenados en la base de datos para el usuario con sesión iniciada.

      Usaremos el nombre del usuario actual y lo enviaremos a la plantilla. Usaremos ese nombre y mostraremos su valor.

      project/main.py

      from flask_login import login_required, current_user
      ...
      @main.route('/profile')
      @login_required
      def profile():
          return render_template('profile.html', name=current_user.name)
      

      A continuación, en el archivo profile.html, actualice la página para mostrar el valor name:

      project/templates/profile.html

      ...
      <h1 class="title">
        Welcome, {{ name }}!
      </h1>
      

      Cuando vayamos a nuestra página de perfil, veremos que aparece el nombre del usuario.

      Página de bienvenida del usuario con el nombre del usuario con sesión iniciada actualmente

      Lo último que podemos hacer es actualizar la vista de cierre de sesión. Podemos invocar la función logout_user para cerrar sesión. Tenemos el decorador @login_required porque no tiene sentido que un usuario cierre una sesión que no inició en primer lugar.

      project/auth.py

      from flask_login import login_user, logout_user, login_required
      ...
      @auth.route('/logout')
      @login_required
      def logout():
          logout_user()
          return redirect(url_for('main.index'))
      

      Tras cerrar sesión e intentar ver la página del perfil, vemos que aparece un mensaje de error. Esto es porque Flask-Login muestra un mensaje intermitente para nosotros cuando el usuario no tiene permiso para acceder a una página.

      Página de inicio con un mensaje que muestra que el usuario debe iniciar sesión para acceder a la página

      Una última cosa que podemos hacer es poner declaraciones if en las plantillas para mostrar solo los enlaces relevantes al usuario. Antes de que el usuario inicie sesión, tendrá la opción de iniciar sesión o registrarse. Tras haber iniciado sesión, el usuario puede ir a su perfil o cerrar sesión:

      templates/base.html

      ...
      <div class="navbar-end">
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.index') }}" class="navbar-item">
              Home
          </a>
          {% if current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.profile') }}" class="navbar-item">
              Profile
          </a>
          {% endif %}
          {% if not current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}" class="navbar-item">
              Login
          </a>
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.signup') }}" class="navbar-item">
              Sign Up
          </a>
          {% endif %}
          {% if current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.logout') }}" class="navbar-item">
              Logout
          </a>
          {% endif %}
      </div>
      

      Página de inicio con la navegación de las páginas Principal, Inicio de sesión y Registro en la parte superior de la pantalla

      Con eso, creó correctamente su aplicación con autenticación.

      Conclusión

      Usamos Flask-Login y Flask-SQLAlchemy para crear un sistema de inicio de sesión para nuestra aplicación. Vimos cómo autenticar a un usuario creando primero un modelo de usuario y almacenando la información del usuario. A continuación, tuvimos que verificar que la contraseña del usuario fuera correcta autenticando la contraseña desde el formulario y comparándola con la almacenada en la base de datos. Finalmente, añadimos autorización a nuestra aplicación usando el decorador @login_required en una página de perfil de forma que solo los usuarios con sesión iniciada puedan verla.

      Lo que creamos en este tutorial será suficiente para aplicaciones más pequeñas pero, si quiere tener más funcionalidad desde el principio, quizá desee considerar usar las bibliotecas Flask-User o Flask-Security, que se desarrollaron a partir de la biblioteca Flask-Login.



      Source link

      Hinzufügen von Authentifizierung zu Ihrer App mit Flask-Login


      Einführung

      Die Möglichkeit für Benutzer, sich bei Ihrer Anwendung anzumelden, ist eine der häufigsten Funktionen, die Sie Ihrer Webanwendung hinzufügen werden. Dieser Artikel behandelt, wie Sie Ihrer Flask-Anwendung mit dem Paket Flask-Login Authentifizierung hinzufügen können.

      Animiertes gif der Flask-Anwendung und des Anmeldefelds

      Wir werden einige Registrierungs- und Anmeldeseiten erstellen, die Benutzern die Anmeldung und den Zugriff auf geschützte Seiten ermöglichen, die nicht angemeldete Benutzer nicht sehen können. Wir werden Informationen aus dem Benutzermodell nehmen und sie auf unseren geschützten Seiten anzeigen, wenn sich der Benutzer anmeldet, um zu simulieren, wie ein Profil aussehen würde.

      In diesem Artikel behandeln wir die folgenden Punkte:

      • Verwenden der Bibliothek Flask-Login für die Sitzungsverwaltung.
      • Verwenden des integrierten Dienstprogramms Flask für das Hashing von Passwörtern.
      • Hinzufügen von geschützten Seiten zu unserer Anwendung nur für angemeldete Benutzer.
      • Verwenden von Flask-SQLAlchemy zum Erstellen eines Benutzermodells.
      • Erstellen von Registrierungs- und Anmeldeformularen für unsere Benutzer zur Erstellung von Konten und zum Anmelden.
      • Zurückgeben von Fehlermeldungen an unsere Benutzer, wenn etwas schiefgeht.
      • Verwenden von Informationen aus dem Konto des Benutzers zur Anzeige auf der Profilseite.

      Der Quellcode für dieses Projekt ist auf GitHub verfügbar.

      Voraussetzungen

      Um dieses Tutorial zu absolvieren, benötigen Sie Folgendes:

      Unsere Anwendung wird das Flask Application Factory-Muster mit Blueprints verwenden. Wir werden eine Blueprint haben, die alles im Zusammenhang mit auth (Authentifizierung) behandelt, und eine weitere für unsere regulären Routen, die den Index und die geschützte Profilseite enthalten. In einer echten Anwendung können Sie die Funktionalität nach Belieben aufschlüsseln, aber die hier behandelte Lösung wird für dieses Tutorial gut funktionieren.

      Hier ist ein Diagramm, das einen Eindruck davon vermittelt, wie die Dateistruktur Ihres Projekts nach Abschluss des Tutorials aussehen wird:

      .
      └── flask_auth_app
          └── project
              ├── __init__.py       # setup our app
              ├── auth.py           # the auth routes for our app
              ├── db.sqlite         # our database
              ├── main.py           # the non-auth routes for our app
              ├── models.py         # our user model
              └── templates
                  ├── base.html     # contains common layout and links
                  ├── index.html    # show the home page
                  ├── login.html    # show the login form
                  ├── profile.html  # show the profile page
                  └── signup.html   # show the signup form
      

      Im weiteren Verlauf des Tutorials werden wir diese Verzeichnisse und Dateien erstellen.

      Schritt 1 — Installieren der Pakete

      Es gibt drei Hauptpakete, die wir für unser Projekt benötigen:

      • Flask
      • Flask-Login: zur Handhabung der Benutzersitzungen nach der Authentifizierung
      • Flask-SQLAlchemy: zur Darstellung des Benutzermodells und als Schnittstelle zu unserer Datenbank

      Wir verwenden SQLite, um keine zusätzlichen Abhängigkeiten für die Datenbank installieren zu müssen.

      Zuerst beginnen wir mit der Erstellung des Projektverzeichnisses:

      Als Nächstes müssen wir zum Projektverzeichnis navigieren:

      Falls Sie keine Python-Umgebung haben, werden Sie eine erstellen wollen. Je nachdem, wie Python auf Ihrem Rechner installiert wurde, werden Ihre Befehle in etwa so aussehen:

      • python3 -m venv auth
      • source auth/bin/activate

      Anmerkung: Sie können das für Ihre lokale Umgebung relevante Tutorial zur Einrichtung von venv konsultieren.

      Führen Sie die folgenden Befehle aus Ihrer virtuellen Umgebung aus, um die erforderlichen Pakete zu installieren:

      • pip install flask flask-sqlalchemy flask-login

      Nachdem Sie die Pakete installiert haben, können Sie nun die Hauptanwendungsdatei erstellen.

      Schritt 2 — Erstellen der Hauptanwendungsdatei

      Beginnen wir mit der Erstellung eines Verzeichnisses project:

      Die erste Datei, an der wir arbeiten, wird die Datei __init__.py für unser Projekt sein:

      Diese Datei wird die Funktion zum Erstellen unserer Anwendung haben, die die Datenbank initialisiert und unsere Blueprints registriert. Im Moment bringt das nicht viel, aber es wird für den Rest unserer Anwendung benötigt. Wir müssen SQLAlchemy initialisieren, einige Konfigurationswerte festlegen und unsere Blueprints registrieren.

      project/__init__.py

      from flask import Flask
      from flask_sqlalchemy import SQLAlchemy
      
      # init SQLAlchemy so we can use it later in our models
      db = SQLAlchemy()
      
      def create_app():
          app = Flask(__name__)
      
          app.config['SECRET_KEY'] = 'secret-key-goes-here'
          app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
      
          db.init_app(app)
      
          # blueprint for auth routes in our app
          from .auth import auth as auth_blueprint
          app.register_blueprint(auth_blueprint)
      
          # blueprint for non-auth parts of app
          from .main import main as main_blueprint
          app.register_blueprint(main_blueprint)
      
          return app
      

      Nachdem wir nun die Hauptanwendungsdatei haben, können wir mit dem Hinzufügen unserer Routen beginnen.

      Schritt 3 — Hinzufügen von Routen

      Für unsere Routen verwenden wir zwei Blueprints. Für unsere Haupt-Blueprint haben wir eine Startseite (/) und eine Profilseite (/profile) für nach der Anmeldung. Versucht der Benutzer, ohne angemeldet zu sein, auf die Profilseite zuzugreifen, wird er auf die Anmeldungsroute umgeleitet.

      Für unsere Auth-Blueprint haben wir Routen, um sowohl die Anmeldeseite (/login) als auch die Registrierungsseite (/sign-up) abzurufen. Außerdem haben wir Routen zur Bearbeitung der POST-Anfragen von beiden Routen. Schließlich haben wir eine Abmeldungsroute (/logout), um einen aktiven Benutzer abzumelden.

      Bis auf Weiteres definieren wir login, signup und logout mit einfachen Rückgaben. Wir werden sie in einem späteren Schritt erneut besuchen und mit der gewünschten Funktionalität aktualisieren.

      Erstellen Sie zunächst main.py für Ihre main_blueprint:

      project/main.py

      from flask import Blueprint
      from . import db
      
      main = Blueprint('main', __name__)
      
      @main.route('/')
      def index():
          return 'Index'
      
      @main.route('/profile')
      def profile():
          return 'Profile'
      

      Erstellen Sie als Nächstes auth.py für Ihre auth_blueprint:

      project/auth.py

      from flask import Blueprint
      from . import db
      
      auth = Blueprint('auth', __name__)
      
      @auth.route('/login')
      def login():
          return 'Login'
      
      @auth.route('/signup')
      def signup():
          return 'Signup'
      
      @auth.route('/logout')
      def logout():
          return 'Logout'
      

      In einem Terminal können Sie die Werte FLASK_APP und FLASK_DEBUG festlegen:

      • export FLASK_APP=project
      • export FLASK_DEBUG=1

      Die Umgebungsvariable FLASK_APP weist Flask an, wie die Anwendung geladen werden soll. Sie sollte darauf zeigen, wo sich create_app befindet. Für unsere Bedürfnisse verweisen wir auf das Projektverzeichnis.

      Die Umgebungsvariable FLASK_DEBUG wird durch Einstellung auf 1 aktiviert. Dadurch wird ein Debugger aktiviert, der Anwendungsfehler im Browser anzeigt.

      Stellen Sie sicher, dass Sie sich im Verzeichnis flask_auth_app befinden, und führen Sie dann das Projekt aus:

      Nun sollten Sie in einem Webbrowser in der Lage sein, zu den fünf möglichen URLs zu navigieren und den zurückgegebenen Text zu sehen, der in auth.py und main.py definiert wurde.

      Wenn Sie beispielsweise localhost:5000/profile besuchen, wird angezeigt: Profile:

      Screenshot des Projekts auf localhost Port 5000 im Browser

      Nachdem wir nun verifiziert haben, dass sich unsere Routen wie erwartet verhalten, können wir mit der Erstellung von Vorlagen fortfahren.

      Schritt 4 — Erstellen von Vorlagen

      Fahren wir damit fort, die Vorlagen zu erstellen, die in unserer Anwendung verwendet werden. Dies ist der erste Schritt, bevor wir die tatsächliche Anmeldefunktionalität implementieren können. Unsere Anwendung verwendet vier Vorlagen:

      • index.html
      • profile.html
      • login.html
      • signup.html

      Außerdem haben wir eine Basisvorlage, die einen gemeinsamen Code für jede der Seiten hat. In diesem Fall wird die Basisvorlage Navigationslinks und das allgemeine Layout der Seite enthalten. Lassen Sie uns diese jetzt erstellen.

      Erstellen Sie zunächst ein Verzeichnis templates in dem Verzeichnis project:

      • mkdir -p project/templates

      Erstellen Sie dann base.html:

      • nano project/templates/base.html

      Fügen Sie als Nächstes den folgenden Code in die Datei base.html ein:

      project/templates/base.html

      <!DOCTYPE html>
      <html>
      
      <head>
          <meta charset="utf-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <title>Flask Auth Example</title>
          <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css" />
      </head>
      
      <body>
          <section class="hero is-primary is-fullheight">
      
              <div class="hero-head">
                  <nav class="navbar">
                      <div class="container">
      
                          <div id="navbarMenuHeroA" class="navbar-menu">
                              <div class="navbar-end">
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.index') }}" class="navbar-item">
                                      Home
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.profile') }}" class="navbar-item">
                                      Profile
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}" class="navbar-item">
                                      Login
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.signup') }}" class="navbar-item">
                                      Sign Up
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.logout') }}" class="navbar-item">
                                      Logout
                                  </a>
                              </div>
                          </div>
                      </div>
                  </nav>
              </div>
      
              <div class="hero-body">
                  <div class="container has-text-centered">
                     {% block content %}
                     {% endblock %}
                  </div>
              </div>
          </section>
      </body>
      
      </html>
      

      Dieser Code erstellt eine Reihe von Menülinks zu jeder Seite der Anwendung und einen Bereich, in dem der Inhalt angezeigt wird.

      Anmerkung: Hinter den Kulissen verwenden wir Bulma, für das Styling und Layout. Für einen tieferen Einblick in Bulma sollten Sie die offizielle Bulma-Dokumentation lesen.

      Erstellen Sie als Nächstes templates/index.html:

      • nano project/templates/index.html

      Fügen Sie der neu erstellten Datei den folgenden Code hinzu, um Inhalte zu der Seite hinzuzufügen:

      project/templates/index.html

      {% extends "base.html" %}
      
      {% block content %}
      <h1 class="title">
        Flask Login Example
      </h1>
      <h2 class="subtitle">
        Easy authentication and authorization in Flask.
      </h2>
      {% endblock %}
      

      Dieser Code erstellt eine grundlegende Indexseite mit einem Titel und einem Untertitel.

      Erstellen Sie als Nächstes templates/login.html:

      • nano project/templates/login.html

      Dieser Code generiert eine Anmeldeseite mit Feldern für E-Mail und Passwort. Es gibt auch ein Kontrollkästchen zur „Erinnerung“ an eine angemeldete Sitzung.

      project/templates/login.html

      {% extends "base.html" %}
      
      {% block content %}
      <div class="column is-4 is-offset-4">
          <h3 class="title">Login</h3>
          <div class="box">
              <form method="POST" action="/login">
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="email" name="email" placeholder="Your Email" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="password" name="password" placeholder="Your Password">
                      </div>
                  </div>
                  <div class="field">
                      <label class="checkbox">
                          <input type="checkbox">
                          Remember me
                      </label>
                  </div>
                  <button class="button is-block is-info is-large is-fullwidth">Login</button>
              </form>
          </div>
      </div>
      {% endblock %}
      

      Erstellen Sie als Nächstes templates/signup.html:

      • nano project/templates/signup.html

      Fügen Sie den folgenden Code hinzu, um eine Registrierungsseite mit Feldern für E-Mail, Namen und Passwort zu erstellen:

      project/templates/signup.html

      {% extends "base.html" %}
      
      {% block content %}
      <div class="column is-4 is-offset-4">
          <h3 class="title">Sign Up</h3>
          <div class="box">
              <form method="POST" action="/signup">
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="email" name="email" placeholder="Email" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="text" name="name" placeholder="Name" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="password" name="password" placeholder="Password">
                      </div>
                  </div>
      
                  <button class="button is-block is-info is-large is-fullwidth">Sign Up</button>
              </form>
          </div>
      </div>
      {% endblock %}
      

      Erstellen Sie als Nächstes templates/profile.html:

      • nano project/templates/profile.html

      Fügen Sie diesen Code hinzu, um eine einfache Seite mit einem Titel zu erstellen, der fest programmiert ist, um Anthony willkommen zu heißen:

      project/templates/profile.html

      {% extends "base.html" %}
      
      {% block content %}
      <h1 class="title">
        Welcome, Anthony!
      </h1>
      {% endblock %}
      

      Später fügen wir Code hinzu, um jeden Benutzer dynamisch zu begrüßen.

      Sobald Sie die Vorlagen hinzugefügt haben, können wir die Return-Anweisungen in jeder der uns zur Verfügung stehenden Routen aktualisieren, um die Vorlage anstelle des Textes zurückzugeben.

      Aktualisieren Sie als Nächstes main.py durch Ändern der Importzeile und der Routen für index und profile:

      project/main.py

      from flask import Blueprint, render_template
      ...
      @main.route('/')
      def index():
          return render_template('index.html')
      
      @main.route('/profile')
      def profile():
          return render_template('profile.html')
      

      Jetzt aktualisieren Sie auth.py durch Ändern der Importzeile und Routen für login und signup:

      project/auth.py

      from flask import Blueprint, render_template
      ...
      @auth.route('/login')
      def login():
          return render_template('login.html')
      
      @auth.route('/signup')
      def signup():
          return render_template('signup.html')
      

      Sobald Sie diese Änderungen vorgenommen haben, sieht die Registrierungsseite wie folgt aus, wenn Sie zu /sign-up navigieren:

      Registrierungsseite unter /signup

      Sie sollten auch die Seiten für /, /login und /profile sehen können.

      Wir lassen /logout vorerst in Ruhe, da es keine Vorlage anzeigt, wenn wir fertig sind.

      Schritt 5 — Erstellen von Benutzermodellen

      Unser Benutzermodell stellt dar, was es für unsere Anwendung bedeutet, einen Benutzer zu haben. Wir haben Felder für eine E-Mail-Adresse, ein Passwort und einen Namen. In Ihrer Anwendung können Sie entscheiden, ob Sie mehr Informationen pro Benutzer speichern möchten. Sie können Dinge wie Geburtstag, Profilbild, Ort oder beliebige Benutzereinstellungen hinzufügen.

      In Flask-SQLAlchemy erstellte Modelle werden durch Klassen dargestellt, die dann in Tabellen in einer Datenbank übersetzt werden. Die Attribute dieser Klassen werden dann zu Spalten für diese Tabellen.

      Lassen Sie uns fortfahren und dieses Benutzermodell erstellen:

      Dieser Code erstellt ein Benutzermodell mit Spalten für id, email, password und name:

      project/models.py

      from . import db
      
      class User(db.Model):
          id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

      Nachdem Sie ein Benutzermodell erstellt haben, können Sie nun mit der Konfiguration Ihrer Datenbank fortfahren.

      Schritt 6 — Konfigurieren der Datenbank

      Wie in den Voraussetzungen angegeben, verwenden wir eine SQLite-Datenbank. Wir könnten selbst eine SQLite-Datenbank erstellen, aber lassen wir das Flask SQLAlchemy für uns erledigen: Wir haben den Pfad der Datenbank bereits in der Datei __init__.py angegeben. Daher müssen wir Flask-SQLAlchemy nur anweisen, die Datenbank in der Python REPL zu erstellen.

      Wenn Sie Ihre Anwendung stoppen und eine Python REPL öffnen, können wir die Datenbank mit der Methode create_all auf dem Objekt db erstellen. Stellen Sie sicher, dass Sie sich immer noch in der virtuellen Umgebung und im Verzeichnis flask_auth_app befinden.

      • from project import db, create_app
      • db.create_all(app=create_app()) # pass the create_app result so Flask-SQLAlchemy gets the configuration.

      Anmerkung: Wenn die Verwendung des Python-Interpreters für Sie neu ist, können Sie die offizielle Dokumentation konsultieren.

      In Ihrem Projektverzeichnis sehen Sie nun eine Datei db.sqlite. Diese Datenbank wird unsere Benutzertabelle enthalten.

      Schritt 7 — Einrichten der Autorisierungsfunktion

      Für unsere Registrierungsfunktion nehmen wir die Daten, die der Benutzer in das Formular eingibt, und und fügen sie unserer Datenbank hinzu. Bevor wir sie hinzufügen, müssen wir sicherstellen, dass der Benutzer nicht bereits in der Datenbank vorhanden ist. Wenn dies nicht der Fall ist, müssen wir sicherstellen, dass wir das Passwort vor dem Hinzufügen in die Datenbank hashen, da wir unsere Passwörter nicht in Klartext speichern möchten.

      Beginnen wir mit dem Hinzufügen einer zweiten Funktion zur Verarbeitung der POST-Formulardaten. In dieser Funktion werden wir zuerst die vom Benutzer übergebenen Daten sammeln.

      Erstellen Sie die Funktion und fügen Sie ein redirect am Ende hinzu. Dies bietet dem Benutzer die Erfahrung einer erfolgreichen Registrierung und die Weiterleitung zu der Anmeldeseite.

      Aktualisieren Sie auth.py durch Ändern der Importzeile und Implementieren von signup_post:

      project/auth.py

      from flask import Blueprint, render_template, redirect, url_for
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          # code to validate and add user to database goes here
          return redirect(url_for('auth.login'))
      

      Fügen wir nun den Rest des Codes hinzu, der für die Registrierung eines Benutzers erforderlich ist.

      Zuerst müssen wir das request-Objekt verwenden, um die Formulardaten zu erhalten.

      Fahren Sie mit der Aktualisierung von auth.py fort, indem Sie Importe hinzufügen und signup_post implementieren:

      auth.py

      from flask import Blueprint, render_template, redirect, url_for, request
      from werkzeug.security import generate_password_hash, check_password_hash
      from .models import User
      from . import db
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          email = request.form.get('email')
          name = request.form.get('name')
          password = request.form.get('password')
      
          user = User.query.filter_by(email=email).first() # if this returns a user, then the email already exists in database
      
          if user: # if a user is found, we want to redirect back to signup page so user can try again
              return redirect(url_for('auth.signup'))
      
          # create a new user with the form data. Hash the password so the plaintext version isn't saved.
          new_user = User(email=email, name=name, password=generate_password_hash(password, method='sha256'))
      
          # add the new user to the database
          db.session.add(new_user)
          db.session.commit()
      
          return redirect(url_for('auth.login'))
      

      Anmerkung: Das Speichern von Passwörtern in Klartext wird als schlechte Sicherheitspraxis angesehen. In der Regel möchten Sie einen komplexen Hash-Algorithmus und ein Passwort-Salt verwenden, um Passwörter sicher zu halten.

      Schritt 8 — Testen der Registrierungsmethode

      Nachdem wir nun die Registrierungsmethode abgeschlossen haben, sollten wir in der Lage sein, einen neuen Benutzer zu erstellen. Verwenden Sie das Formular, um einen Benutzer zu erstellen.

      Es gibt zwei Möglichkeiten, wie Sie überprüfen können, ob die Registrierung funktioniert: Sie können einen Datenbankbetrachter verwenden, um die Zeile anzuzeigen, die Ihrer Tabelle hinzugefügt wurde, oder Sie können versuchen, sich mit der gleichen E-Mail-Adresse erneut zu registrieren. Wenn Sie einen Fehler erhalten, wissen Sie, dass die erste E-Mail korrekt gespeichert wurde. Lassen Sie uns also diesen Ansatz wählen.

      Wir können Code hinzufügen, um dem Benutzer mitzuteilen, dass die E-Mail bereits existiert und ihm sagen, dass er zur Anmeldeseite gehen soll. Durch Aufruf der Funktion flash senden wir eine Nachricht an die nächste Anfrage, die in diesem Fall die Weiterleitung „redirect“ ist. Die Seite, auf der wir landen, wird dann Zugriff auf diese Nachricht in der Vorlage haben.

      Zuerst fügen wir die Funktion flash hinzu, bevor wir zurück zu unserer Registrierungsseite umleiten.

      project/auth.py

      from flask import Blueprint, render_template, redirect, url_for, request, flash
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          ...
          if user: # if a user is found, we want to redirect back to signup page so user can try again
              flash('Email address already exists')
              return redirect(url_for('auth.signup'))
      

      Um die geflashte Nachricht in der Vorlage zu erhalten, können wir diesen Code oberhalb des Formulars hinzufügen. Dadurch wird die Nachricht direkt über dem Formular angezeigt.

      project/templates/signup.html

      ...
      {% with messages = get_flashed_messages() %}
      {% if messages %}
          <div class="notification is-danger">
              {{ messages[0] }}. Go to <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}">login page</a>.
          </div>
      {% endif %}
      {% endwith %}
      <form method="POST" action="/signup">
      

      Registrierungsfeld, das eine Nachricht anzeigt „E-Mail-Adresse bereits vorhanden. Gehen Sie zur Anmeldeseite“ in einem dunkel-rosa Feld

      Schritt 9 — Hinzufügen der Anmeldemethode

      Die Anmeldemethode ähnelt der Registrierungsfunktion insofern, als dass wir die Benutzerinformationen nehmen und etwas damit tun. In diesem Fall vergleichen wir die eingegebene E-Mail-Adresse, um zu sehen, ob sie in der Datenbank enthalten ist. Wenn dies der Fall ist, testen wir das vom Benutzer bereitgestellte Passwort, indem wir das vom Benutzer eingegebene Passwort hashen und es mit dem gehashten Passwort in der Datenbank vergleichen. Wenn beide gehaschten Passwörter übereinstimmen, wissen wir, dass der Benutzer das korrekte Passwort eingegeben hat.

      Sobald der Benutzer die Passwort-Überprüfung bestanden hat, wissen wir, dass er die richtigen Anmeldedaten hat und wir können in mit Flask-Login anmelden. Durch den Aufruf von login_user erstellt Flask-Login eine Sitzung für diesen Benutzer, die bestehen bleibt, während der Benutzer angemeldet bleibt, wodurch der Benutzer geschützte Seiten einsehen kann.

      Wir können mit einer neuen Route für den Umgang mit den gePOSTeten Dateien beginnen. Wenn sich der Benutzer erfolgreich anmeldet, leiten wir zur Profilseite weiter.

      project/auth.py

      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          # login code goes here
          return redirect(url_for('main.profile'))
      

      Nun müssen wir überprüfen, ob der Benutzer die richtigen Anmeldedaten hat:

      project/auth.py

      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          email = request.form.get('email')
          password = request.form.get('password')
          remember = True if request.form.get('remember') else False
      
          user = User.query.filter_by(email=email).first()
      
          # check if the user actually exists
          # take the user-supplied password, hash it, and compare it to the hashed password in the database
          if not user or not check_password_hash(user.password, password):
              flash('Please check your login details and try again.')
              return redirect(url_for('auth.login')) # if the user doesn't exist or password is wrong, reload the page
      
          # if the above check passes, then we know the user has the right credentials
          return redirect(url_for('main.profile'))
      

      Fügen wir den Block in der Vorlage hinzu, damit der Benutzer die geflashte Nachricht sehen kann. Wie bei dem Registrierungsformular fügen wir die potenzielle Fehlermeldung direkt über dem Formular hinzu:

      project/templates/login.html

      ...
      {% with messages = get_flashed_messages() %}
      {% if messages %}
          <div class="notification is-danger">
              {{ messages[0] }}
          </div>
      {% endif %}
      {% endwith %}
      <form method="POST" action="/login">
      

      Wir haben nun die Möglichkeit zu sagen, dass ein Benutzer erfolgreich angemeldet wurde, aber es ist nichts vorhanden, wo der Benutzer protokolliert werden kann. Hier bringen wir Flask-Login zur Verwaltung von Benutzersitzungen ein.

      Bevor wir beginnen, benötigen wir einige Dinge, damit Flask-Login funktioniert. Beginnen Sie mit dem Hinzufügen des UserMixin zu Ihrem Benutzermodell. Das UserMixin fügt dem Modell Flask-Login-Attribute hinzu, sodass Flask-Login damit arbeiten kann.

      models.py

      from flask_login import UserMixin
      from . import db
      
      class User(UserMixin, db.Model):
          id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

      Dann müssen wir unseren User-Loader angeben. Ein User-Loader teilt Flask-Login mit, wie ein bestimmter Benutzer anhand der in seinem Sitzungs-Cookie gespeicherten ID gefunden werden kann. Wir können dies in unserer Funktion create_app zusammen mit dem Code init für Flask-Login hinzufügen:

      project/__init__.py

      ...
      from flask_login import LoginManager
      ...
      def create_app():
          ...
          db.init_app(app)
      
          login_manager = LoginManager()
          login_manager.login_view = 'auth.login'
          login_manager.init_app(app)
      
          from .models import User
      
          @login_manager.user_loader
          def load_user(user_id):
              # since the user_id is just the primary key of our user table, use it in the query for the user
              return User.query.get(int(user_id))
      

      Schließlich können wir die Funktion login_user hinzufügen, kurz bevor wir auf die Profilseite zur Erstellung der Sitzung weiterleiten:

      project/auth.py

      from flask_login import login_user
      from .models import User
      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          ...
          # if the above check passes, then we know the user has the right credentials
          login_user(user, remember=remember)
          return redirect(url_for('main.profile'))
      

      Mit der Einrichtung von Flask-Login können wir die Route /login verwenden. Wenn alles eingerichtet ist, sehen Sie die Profilseite.

      Profilseite mit „Willkommen, Anthony!“

      Schritt 10 — Schützen von Seiten

      Wenn Ihr Name nicht auch Anthony ist, werden Sie feststellen, dass Ihr Name falsch ist. Wir möchten, dass das Profil den Namen in der Datenbank anzeigt. Zuerst müssen wir also die Seite schützen und dann auf die Daten des Benutzers zugreifen, um den Namen zu erhalten.

      Um eine Seite bei der Verwendung von Flask-Login zu schützen, fügen wir den Dekorator @login_requried zwischen der Route und der Funktion hinzu. Dadurch wird verhindert, dass ein nicht angemeldeter Benutzer die Route sehen kann. Wenn der Benutzer nicht angemeldet ist, wird der Benutzer gemäß der Flask-Login-Konfiguration auf die Anmeldeseite weitergeleitet.

      Bei Routen, die mit dem Dekorator @login_required versehen sind, haben wir dann die Möglichkeit, das Objekt current_user innerhalb der Funktion zu verwenden. Dieser current_user stellt den Benutzer aus der Datenbank dar und wir können mit der Punktnotation auf alle Attribute dieses Benutzers zugreifen. Beispielsweise geben current_user.email, current_user.password und current_user.name sowie current_user.id die tatsächlichen Werte zurück, die in der Datenbank für den angemeldeten Benutzer gespeichert sind.

      Verwenden wir den Namen des aktuellen Benutzers und senden ihn an die Vorlage. Dann verwenden wir diesen Namen und zeigen seinen Wert an.

      project/main.py

      from flask_login import login_required, current_user
      ...
      @main.route('/profile')
      @login_required
      def profile():
          return render_template('profile.html', name=current_user.name)
      

      Aktualisieren Sie dann in der Datei profile.html die Seite, um den Wert name anzuzeigen:

      project/templates/profile.html

      ...
      <h1 class="title">
        Welcome, {{ name }}!
      </h1>
      

      Sobald wir zu unserer Profilseite gehen, sehen wir, dass der Name des Benutzers angezeigt wird.

      Begrüßungsseite für den Benutzer mit dem Namen des aktuell angemeldeten Benutzers

      Als Letztes können wir die Abmelde-Ansicht aktualisieren. Wir können die Funktion logout_user in einer Route zur Abmeldung aufrufen. Wir haben den Dekorator @login_required, weil es keinen Sinn macht, einen Benutzer abzumelden, der nicht zuerst angemeldet ist.

      project/auth.py

      from flask_login import login_user, logout_user, login_required
      ...
      @auth.route('/logout')
      @login_required
      def logout():
          logout_user()
          return redirect(url_for('main.index'))
      

      Nachdem wir uns abgemeldet und versucht haben, die Profilseite erneut anzuzeigen, wird eine Fehlermeldung angezeigt. Dies liegt daran, dass Flask-Login eine Nachricht für uns anzeigt, wenn der Benutzer nicht auf eine Seite zugreifen darf.

      Anmeldeseite mit einer Nachricht, die zeigt, dass sich der Benutzer anmelden muss, um auf die Seite zuzugreifen.

      Eine letzte Sache, die wir tun können, ist, if-Anweisungen in die Vorlage aufzunehmen, um nur die für den Benutzer relevanten Links anzuzeigen. Bevor sich der Benutzer also anmeldet, hat er die Möglichkeit, sich anzumelden oder zu registrieren. Nach der Anmeldung können Benutzer zu ihrem Profil gehen oder sich abmelden:

      templates/base.html

      ...
      <div class="navbar-end">
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.index') }}" class="navbar-item">
              Home
          </a>
          {% if current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.profile') }}" class="navbar-item">
              Profile
          </a>
          {% endif %}
          {% if not current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}" class="navbar-item">
              Login
          </a>
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.signup') }}" class="navbar-item">
              Sign Up
          </a>
          {% endif %}
          {% if current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.logout') }}" class="navbar-item">
              Logout
          </a>
          {% endif %}
      </div>
      

      Startseite mit der Navigation Start, Anmeldung und Registrierung oben auf dem Bildschirm

      Damit haben Sie Ihre Anwendung mit Authentifizierung erfolgreich erstellt.

      Zusammenfassung

      Wir haben Flask-Login und Flask-SQLAlchemy verwendet, um ein Anmeldesystem für unsere Anwendung zu erstellen. Wir haben behandelt, wie ein Benutzer authentifiziert werden kann, indem wir zuerst ein Benutzermodell erstellen und die Benutzerinformationen speichern. Dann mussten wir verifizieren, dass das Passwort des Benutzers korrekt war, indem wir das Passwort aus dem Formular gehasht und mit dem in der Datenbank gespeicherten Benutzer verglichen haben. Schließlich haben wir unserer Anwendung Autorisierung hinzugefügt, indem wir den Dekorator @login_required auf einer Profilseite verwenden, damit nur angemeldete Benutzer diese Seite sehen können.

      Was wir in diesem Tutorial erstellt haben, wird für kleinere Anwendungen ausreichen. Wenn Sie jedoch von Anfang an mehr Funktionalität haben möchten, sollten Sie möglicherweise die Bibliotheken Flask-User oder Flask-Security verwenden, die beide auf der Bibliothek Flask-Login aufbauen.



      Source link