Tutorial

Cara Menambah Autentikasi pada Aplikasi Anda dengan Flask-Login

Published on December 2, 2020
author

Anthony Herbert

Bahasa Indonesia
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:

  1. mkdir flask_auth_app

Selanjutnya, kita perlu bernavigasi ke direktori proyek:

  1. cd flask_auth_app

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

  1. python3 -m venv auth
  2. 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:

  1. 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:

  1. mkdir project

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

  1. nano project/__init__.py

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:

  1. nano project/main.py
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:

  1. nano project/auth.py
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:

  1. export FLASK_APP=project
  2. 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:

  1. flask run

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:

  1. mkdir -p project/templates

Kemudian, ciptakan base.html:

  1. 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="{{ url_for('main.index') }}" class="navbar-item">
                                Home
                            </a>
                            <a href="{{ url_for('main.profile') }}" class="navbar-item">
                                Profile
                            </a>
                            <a href="{{ url_for('auth.login') }}" class="navbar-item">
                                Login
                            </a>
                            <a href="{{ url_for('auth.signup') }}" class="navbar-item">
                                Sign Up
                            </a>
                            <a href="{{ 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:

  1. 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:

  1. 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:

  1. 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:

  1. 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:

  1. nano project/models.py

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.

  1. from project import db, create_app, models
  2. 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="{{ url_for('auth.login') }}">login page</a>.
    </div>
{% endif %}
{% endwith %}
<form method="POST" action="/signup">

Kotak pendaftaran menampilkan pesan "Email address already exists. Go to login page" dalam kotak merah muda yang gelap

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 "Welcome, Anthony!"

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="{{ url_for('main.index') }}" class="navbar-item">
        Home
    </a>
    {% if current_user.is_authenticated %}
    <a href="{{ url_for('main.profile') }}" class="navbar-item">
        Profile
    </a>
    {% endif %}
    {% if not current_user.is_authenticated %}
    <a href="{{ url_for('auth.login') }}" class="navbar-item">
        Login
    </a>
    <a href="{{ url_for('auth.signup') }}" class="navbar-item">
        Sign Up
    </a>
    {% endif %}
    {% if current_user.is_authenticated %}
    <a href="{{ 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.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Anthony Herbert

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.