One place for hosting & domains

      FlaskLogin

      Authentication and Authorization With Flask-Login

      Introduction

      Allowing users to log in to your app is one of the most common features you’ll add to a web app you build. This article will cover how to add simple authentication to your Flask app. The main package we will use to accomplish this is Flask Login.

      We’re going to build some signup and login pages that allow our app to allow users to log in and access protected pages that non-logged-in users can see. We’ll grab information from the user model and display it on our protected pages when the user logs in to simulate what a profile would look like.

      We will cover the following in this article:

      • Use the Flask-Login library for session management
      • Use the built-in Flask utility for hashing passwords
      • Add protected pages to our app for logged in users only
      • Use Flask-SQLAlchemy to create a user model
      • Create sign up and login forms for our users to create accounts and log in
      • Flash error messages back to users when something goes wrong
      • Use information from the user’s account to display on the profile page

      Our app will use the Flask app factory pattern with blueprints. We’ll have one blueprint that handles everything auth-related, and we’ll have another blueprint for our regular routes, which include the index and the protected profile page. In a real app, of course, you can break down the functionality in any way you like, but what I’ve proposed will work well for this tutorial.

      To start, we need to create the directories and files for our project.

      - project
      ---- templates
      -------- base.html 
      -------- index.html 
      -------- login.html 
      -------- profile.html 
      -------- signup.html 
      ---- __init__.py 
      ---- auth.py 
      ---- main.py 
      ---- models.py 
      

      You can create those files and we’ll add them as we progress along.

      There are three main packages we need for our project:

      • Flask
      • Flask-Login – to handle the user sessions after authentication
      • Flask-SQLAlchemy – to represent the user model and interface with our database

      We’ll only be using SQLite for the database to avoid having to install any extra dependencies for the database. Here’s what you need to run after creating your virtual environment to install the packages.

      1. pip install flask flask-sqlalchemy flask-login

      Let’s start by creating the __init__.py file for our project. This will have the function to create our app which will initialize the database and register our blueprints. At the moment this won’t do much, but it will be needed for the rest of our app. All we need to do is initialize SQLAlchemy, set some configuration values, and register our blueprints here.

      __init__.py

      __init__.py

      from flask import Flask__
      from flask_sqlalchemy import SQLAlchemy
      
      
      db = SQLAlchemy()
      
      def create_app():
          app = Flask(__name__)
      
          app.config['SECRET_KEY'] = '9OLWxND4o83j4K4iuopO'
          app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
      
          db.init_app(app)
      
          
          from .auth import auth as auth_blueprint
          app.register_blueprint(auth_blueprint)
      
          
          from .main import main as main_blueprint
          app.register_blueprint(main_blueprint)
      
          return app
      

      Now that we have the main app file, we can start adding in our routes.

      For our routes, we’ll use two blueprints. For our main blueprint, we’ll have a home page (/) and profile page (/profile) after we log in. If the user tries to access the profile page without being logged in, they’ll be sent to our login route.

      For our auth blueprint, we’ll have routes to retrieve both the login page (/login) and the signup page (/signup). We’ll also have routes for handling the POST request from both of those two routes. Finally, we’ll have a logout route (/logout) to log out an active user.

      Let’s go ahead and add them even though they won’t do much. Later we will update them so we can use them.

      main.py

      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'
      

      auth.py

      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'
      

      You can now set the FLASK_APP and FLASK_DEBUG values and run the project. You should be able to view navigate to the five possible URLs and see the text returned.

      1. export FLASK_APP=project
      2. export FLASK_DEBUG=1
      3. flask run

      Let’s go ahead and create the templates that are used in our app. This is the first step before we can implement the actual login functionality. Our app will use four templates:

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

      We’ll also have a base template that will have code common to each of the pages. In this case, the base template will have navigation links and the general layout of the page. Let’s create them now.

      templates/base.html

      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>
      

      templates/index.html

      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 %}
      

      templates/login.html

      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 %}
      

      templates/signup.html

      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 %}
      

      templates/profile.html

      templates/profile.html

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

      Once you’ve added the templates, we can update the return statements in each of the routes we have to return the templates instead of the text.

      main.py

      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')
      

      auth.py

      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')
      

      For example, here is what the signup page looks like if you navigate to /signup. You should be able to see the pages for /, /login, and /profile as well. We’ll leave /logout alone for now because it won’t display a template when it’s done.

      Our user model represents what it means for our app to have a user. To keep it simple, we’ll have fields for an email address, password, and name. Of course in your application, you may decide you want much more information to be stored per user. You can add things like birthday, profile picture, location, or any user preferences.

      Models created in Flask-SQLAlchemy are represented by classes which then translate to tables in a database. The attributes of those classes then turn into columns for those tables.

      Let’s go ahead and create that user model.

      models.py

      models.py

      from . import db
      
      class User(db.Model):
          id = db.Column(db.Integer, primary_key=True) 
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

      Like I said before, we’ll be using a SQLite database. We could create a SQLite database on our own, but let’s have Flask-SQLAlchemy do it for us.

      We already have the path of the database specified in the __init__.py file, so we just need to tell Flask-SQLAlchemy to create the database for us in the Python REPL.

      If you stop your app and open up a Python REPL, we can create the database using the create_all method on the db object.

      from project import db, create_app
      db.create_all(app=create_app()) 
      

      You should now see a db.sqlite file in your project directory. This database will have our user table in it.

      Now that we have everything set up, we can finally get to writing the code for the authorization.

      For our sign-up function, we’re going to take the data the user types into the form and add it to our database. But before we add it, we need to make sure the user doesn’t already exist in the database. If it doesn’t, then we need to make sure we hash the password before placing it into the database, because we don’t want our passwords stored in plaintext.

      Let’s start by adding a second function to handle the POSTed form data. In this function, we will gather the data passed from the user first.

      Let’s start by creating the function and adding a redirect to the bottom because we know when we add the user to the database, we will redirect to the login route.

      auth.py

      auth.py

      from flask import Blueprint, render_template, redirect, url_for
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          
          return redirect(url_for('auth.login'))
      

      Now, let’s add the rest of the code necessary for signing up a user.

      To start, we’ll have to use the request object to get the form data. If you’re not familiar with the request object, I wrote an article on it here: How To Process Incoming Request Data in Flask

      auth.py

      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 user: 
              return redirect(url_for('auth.signup'))
      
          
          new_user = User(email=email, name=name, password=generate_password_hash(password, method='sha256'))
      
          
          db.session.add(new_user)
          db.session.commit()
      
          return redirect(url_for('auth.login'))
      

      Now that we have the signup method done, we should be able to create a new user. Use the form to create a user.

      There are two ways you can verify if the sign up worked: you can use a database viewer to look at the row that was added to your table, or you can simply try signing up with the same email address again, and if you get an error, you know the first email was saved properly. So let’s take that approach.

      We can add code to let the user know the email already exists and tell them to go to the login page. By calling the flash function, we will send a message to the next request, which in this case, is the redirect. The page we land on will then have access to that message in the template.

      First, we add the flash before we redirect back to our signup page.

      auth.py

      auth.py

      from flask import Blueprint, render_template, redirect, url_for, request, flash
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          ...
          if user: 
              flash('Email address already exists')
              return redirect(url_for('auth.signup'))
      

      To get the flashed message in the template, we can add this code above the form. This will display the message directly above the form.

      templates/signup.html

      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">
      ...
      

      The login method is similar to the signup function in that we will take the user information and do something with it. In this case, we will compare the email address entered to see if it’s in the database. If so, we will test the password the user provided by hashing the password the user passes in and comparing it to the hashed password in the database. We know the user has entered the correct password when both hashed passwords match.

      Once the user has passed the password check, we know that they have the correct credentials and we can go ahead and log them in using Flask-Login. By calling login_user, Flask-Login will create a session for that user that will persist as the user stays logged in, which will allow the user to view protected pages.

      We can start with a new route for handling the POSTed data. We’ll redirect to the profile page when the user successfully logs in.

      auth.py

      auth.py

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

      Now, we need to verify if the user has the correct credentials.

      auth.py

      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()
      
          
          
          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')) 
      
          
          return redirect(url_for('main.profile'))
      

      Let’s add in the block in the template so the user can see the flashed message. Like the signup form, let’s add the potential error message directly above the form.

      templates/login.html

      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">
      

      So we have the ability to say a user has been logged in successfully, but there is nothing to actually log the user in anywhere. This is where we bring in Flask-Login.

      But first, we need a few things for Flask-Login to work.

      We start by adding something called the UserMixin to our User model. The UserMixin will add Flask-Login attributes to our model so Flask-Login will be able to work with it.

      models.py

      models.py

      from flask_login import UserMixin
      from . import db
      
      class User(UserMixin, db.Model):
          id = db.Column(db.Integer, primary_key=True) 
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

      Then, we need to specify our user loader. A user loader tells Flask-Login how to find a specific user from the ID that is stored in their session cookie. We can add this in our create_app function along with basic init code for Flask-Login.

      __init__.py

      __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):
              
              return User.query.get(int(user_id))
      

      Finally, we can add the login_user function just before we redirect to the profile page to create the session.

      auth.py

      auth.py

      from flask_login import login_user
      from .models import User
      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          
          login_user(user, remember=remember)
          return redirect(url_for('main.profile'))
      

      With Flask-Login setup, we can finally use the /login route.

      When everything is successful, we will see the profile page.

      If your name isn’t also Anthony, then you’ll see that your name is wrong. What we want is the profile to display the name in the database. So first, we need to protect the page and then access the user’s data to get the name.

      To protect a page when using Flask-Login is very simple: we add the @login_requried decorator between the route and the function. This will prevent a user who isn’t logged in from seeing the route. If the user isn’t logged in, the user will get redirected to the login page, per the Flask-Login configuration.

      With routes that are decorated with the login_required decorator, we then have the ability to use the current_user object inside of the function. This current_user represents the user from the database, and we can access all of the attributes of that user with dot notation. For example, current_user.email, current_user.password, current_user.name, and current_user.id will return the actual values stored in the database for the logged-in user.

      Let’s use the name of the current user and send it to the template. We then will use that name and display its value.

      main.py

      main.py

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

      templates/profile.html

      templates/profile.html

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

      Once we go to our profile page, we then see that the user’s name appears.

      The final thing we can do is update our logout view. We can call the logout_user function in a route for logging out. We have the login_required decorator because it doesn’t make sense to log out a user who isn’t logged in, to begin with.

      auth.py

      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'))
      

      After we log out and try viewing the profile page again, we see an error message appear. This is because Flask-Login flashes a message for us when the user isn’t allowed to access a page.

      One last thing we can do is put if statements in the templates to display only the links relevant to the user. So before the user logins in, they will have the option to log in or signup. After they have logged in, they can go to their profile or log out.

      templates/base.html

      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>
      

      We’ve done it! We have used Flask-Login and Flask-SQLAlchemy to build a very basic login system for our app. We covered how to authenticate a user by first creating a user model and storing the user information for later. Then we had to verify the user’s password was correct by hashing the password from the form and comparing it to the one stored in the database. Finally, we added authorization to our app by using the @login_required decorator on a profile page so only logged-in users can see that page.

      What we created in this tutorial will be sufficient for smaller apps, but if you wish to have more functionality from the beginning, you may want to consider using either the Flask-User or Flask-Security libraries, which are both build on top of the Flask-Login library.

      Flask-Login を使用してアプリケーションに認証を追加する方法


      はじめに

      ユーザーがアプリケーションにログインできるようにすることは、Webアプリケーションに追加する最も一般的な機能の一つです。この記事では、Flask-Loginパッケージを使用してFlaskアプリケーションに認証を追加する方法を説明します。

      Animated gif of the Flask app and login box

      ログインしていないユーザーは見ることができない保護されたページに、ユーザーがログインしてアクセスできる、サインアップとログインページを構築します。ユーザーモデルから情報を取得し、ユーザーがログインした時にプロファイルがどのように見えるかを保護されたページに表示してシミュレーションします。

      この記事では、次のことを説明します。

      • セッション管理に Flask-Login ライブラリを使用
      • 組み込み Flask ユティリティを使用して、パスワードをハッシュするときに使用
      • ログインしているユーザーのみがアクセスできる保護されたページをアプリケーションに追加
      • Flask-SQLAlchemy を使用して、ユーザーモデルを作成
      • アカウントを作成してログインするユーザーのためにサインアップとログインフォームを作成
      • 問題が発生したとき、ユーザーにエラーメッセージを戻す
      • ユーザーのアカウントから情報を使用して、 プロファイルページに表示

      このプロジェクトのソースコードは、GitHub 入手可能です。

      前提条件

      このチュートリアルには、次が必要です。

      アプリケーションは、ブループリントにより Flask アプリケーションのファクトリーパターンを使用します。認証と関連するすべてを処理するブループリントがあり、インデックスと保護されたプロファイルページを含む通常のルートには別のものがあります。実際のアプリケーションでは、好きなように機能を分類することができますが、ここで説明されているソリューションはこのチュートリアルでうまく機能します。

      チュートリアル完了後の、プロジェクトのファイル構造イメージは次のダイアグラムをご覧ください。

      .
      └── 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
      

      チュートリアルにおいて、こういったディレクトリとファイルを作成します。

      ステップ 1— パッケージをインストール

      プロジェクトに必要な主要なパッケージが 3 つあります。

      • Flask
      • Flask-Login: 認証後のユーザーセッションを処理
      • Flask-SQLAlchemy: データベースでユーザーモデルとインターフェースを表示

      データベースの更なる依存関係をインストールする必要を避けるために、SQLite を使用します。

      まず、プロジェクトディレクトリの作成から始めます。

      次に、プロジェクトディレクトリに移動する必要があります。

      プロジェクトディレクトリがない場合、Python 環境を作ります。マシンに Python がどのようにインストールされているかによって、次のようなコマンドになります。

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

      注意:venvの設定については、ローカル環境に関連するチュートリアルを参照してください。

      必要なパッケージをインストールするには、仮想環境から次のコマンドを実行します。

      • pip install flask flask-sqlalchemy flask-login

      パッケージをインストールしたので、メインアプリケーションファイルを作成する準備ができました。

      ステップ 2 — メインアプリケーションファイルの作成

      プロジェクトディレクトリの作成から始めましょう。

      最初にはじめるファイルは、プロジェクトの__init__.pyファイルになります。

      このファイルには、データベースを初期化してブループリントを登録するというアプリケーションを作成する機能があります。現時点でそれほど必要ありませんが、アプリケーション完成には必要となります。ここでは SQLAlchemy を初期化し、設定値を設定し、ブループリントを登録する必要があります。

      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
      

      メインアプリケーションファイルがあるので、ルート内で追加を開始します。

      ステップ 3 — ルートの追加

      ルートについては、2 つのブループリントを使用します。メインブループリントについては、ログインの後にホームページ(/)とプロファイルページ (/profile)が作成されます。ユーザーがログインせずにプロファイルページにアクセスしようとする場合、ログインルートに戻ります。

      認証ブループリントについては、ログインページ(/login)とサインアップページ( /sign-up)の両方を取得するルートがあります。これらの 2 つのルートから POST 要求を処理するルートもあります。最後に、アクティブなユーザーをログアウトするログアウトルート(/logout)があります。

      とりあえずは、簡単な返り値でログインサインアップログアウトを定義します。後にこれに再度アクセスし、希望の機能を使用して更新します。

      まず、main_blueprint のために 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'
      

      次に、auth_blueprint のために 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'
      

      端末では、FLASK_APPFLASK_DEBUG の値を設定できます。

      • export FLASK_APP=project
      • export FLASK_DEBUG=1

      FLASK_APP 環境変数は、アプリケーションをロードする方法を説明します。これは、create_app の場所を指します。ここでは、プロジェクトディレクトリを指します。

      FLASK_DEBUG 環境変数は、1 に設定することで有効となります。 これにより、ブラウザでアプリケーションエラーを表示するデバッガを有効にします。

      flask_auth_app ディレクトリに存在することを確認し、プロジェクトを実行します。

      これでWebブラウザでは、5つの潜在的なURLに移動し、auth.pymain.py で定義されたテキストを参照できます。

      たとえば、localhost:5000/profile にアクセスするとProfileを表示します。

      Screenshot of project at localhost port 5000 in browser

      ルートが予想通りに動作していることを確認したため、テンプレート作成に進みます。

      ステップ 4 —テンプレート作成

      アプリケーションで使用されるテンプレートを作成しましょう。これは、実際のログイン機能を実装する前の最初のステップです。アプリケーションは 4つのテンプレートを使用します。

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

      また、ページごとにコードがあるベーステンプレートもあります。この場合、ベーステンプレートには、ナビゲーションリンクとページの一般的なレイアウトがあります。それでは作成しましょう。

      まず、projectディレクトリの下にtemplatesディレクトリを作成します。

      • mkdir -p project/templates

      次に、base.html を作成します。

      • nano project/templates/base.html

      次に、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>
      

      このコードは、アプリケーションとコンテンツが表示されるエリアの各ページに一連のメニューリンクを作成します。

      注意:シーンの背後には、スタイリングとレイアウトを処理するために Bulma を使用します。Bulma についての詳細は、公式の Bulma のドキュメントを参照してください。

      次に、templates/index.html を作成します。

      • nano project/templates/index.html

      ページにコンテンツを追加するために、新しいファイルを作成するには次のコードを追加します。

      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 %}
      

      このコードは、タイトルとサブタイトルを含む基本的なインデックスページを作成します。

      次に、templates/login.html を作成します。

      • nano project/templates/login.html

      このコードは、メールパスワードのフィールドを含むログインページを生成します。セッション中のログインを「記憶」するためのチェックボックスもあります。

      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 %}
      

      次に、templates/signup.html を作成します。

      • nano project/templates/signup.html

      メール、名前、パスワードのフィールドを含むサインアップページを作成するには、次のコードを追加します。

      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 %}
      

      次に、templates/profile.html を作成します。

      • nano project/templates/profile.html

      このコードを追加して、Anthony を歓迎するためにハードコーディングされているタイトルを含むシンプルなページを作成します。

      project/templates/profile.html

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

      その後、任意のユーザーを動的に迎えるためにコードを追加します。

      テンプレートを追加したら、テキストではなくテンプレートを返す必要がある各ルート内のreturn文を更新できます。

      次に、indexprofileのインポートラインとルートを変更して main.py を更新します。

      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')
      

      loginsignupのインポートラインとルートを変更して、auth.py を更新します。

      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')
      

      変更すると、/sign-up に移動する場合サインアップページは以下のように表示されます。

      Sign up page at /signup

      //login/profile のページも表示できるはずです。

      ここでは、完了したときにテンプレートが表示されないので、/logout は残します。

      ステップ 5 —ユーザーモデルの作成

      ユーザーモデルは、アプリケーションにユーザーがいることを意味します。メールアドレス、パスワード、名前のフィールドがあります。アプリケーションでは、ユーザーごとに保存されるより多くの情報を決定することができます。誕生日、プロファイル画像、場所、またはユーザーの好みなどを追加できます。

      Flask-SQLAlchemy で作成されたモデルはクラスにより表され、データベースのテーブルに変換されます。これらのクラスの属性はその後、こうしたテーブルの列に変わります。

      次に進み、このユーザーモデルを作成しましょう。

      このコードは、idemailpasswordnameの列があるユーザーモデルを作成します。

      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))
      

      ユーザーモデルを作成した後は、データベースの設定に進みます。

      ステップ 6 — データベースの設定

      前提条件に記載されているように、SQLite データベースを使用します。独自の SQLite データベースを作成できますが、Flask-SQLAlchemy を使用しましょう。__init__.py ファイルで指定されたデータベースのパスがあるため、Python REPLでデータベースを作成するには、Flask-SQLAlchemyを指示する必要があります。

      アプリケーションを停止してPython REPLを開いた場合、db オブジェクトのcreate_all メソッドを使用してデータベースを作成できます。まだ仮想環境と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.

      注意: Python インタプリタを使用する場合には、公式ドキュメントを参照してください。

      これで、プロジェクトディレクトリにdb.sqlite が表示されます。このデータベースの中にはユーザーテーブルがあります。

      ステップ 7 — 認証機能の設定

      サインアップ機能については、ユーザーのタイプをフォームに入力し、データベースに追加します。追加する前に、ユーザーがデータベースに存在しないことを確認する必要があります。ユーザーがいない場合は、プレーンテキストにパスワードを保存することは望ましくないため、データベースに追加する前にパスワードをハッシュすることを確認する必要があります。

      POSTフォームデータを処理するために、2 つ目の関数を追加しましょう。この機能では、最初にユーザーから渡されたデータを収集します。

      関数を作成して、下部にリダイレクトを追加します。これにより、より良いサインアップのユーザー体験と、ログインページに誘導されます。

      インポートラインを変更し signup_post を実行することで auth.py を更新します。

      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'))
      

      これで、ユーザーのサインアップに必要なコードの残りを追加しましょう。

      まず、フォームデータを取得するために、リクエストオブジェクトを使用する必要があります。

      インポートを追加して signup_post を実行するために auth.py の更新を続けます。

      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'))
      

      注意: plaintext へのパスワードの保存は、セキュリティの是正すべき実行と見なされます。一般的に、パスワードを安全に保つために複雑なハッシュアルゴリズムとパスワードソルトを使用します。

      ステップ 8 — サインアップの方法のテスト

      サインアップの方法が完了したため、新しいユーザーを作成することができます。フォームを使用して、ユーザーを作成します。

      サインアップが機能したかどうかを確認する 2 つの方法があります。1つは、データベースビューアを使用して、テーブルに追加された行を調べます。または、同じメールアドレスで再度サインアップを試行します。エラーが発生した場合、最初のメールが適切に保存されたこととなります。では、そのアプローチをしてみましょう。

      メールがすでに存在していることをユーザーに知らせ、ログインページに移動するようにユーザーに指示するためにコードを追加することができます。flash機能を呼び出すことで、次の要求にメッセージを送信します。この場合、リダイレクトとなります。このページに移動し、テンプレート内のメッセージにアクセスします。

      まず、サインアップページにリダイレクトする前にflashを追加します。

      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'))
      

      テンプレートで点滅したメッセージを取得するには、フォーム上のこのコードを追加することができます。これは、フォーム上のメッセージを直接表示します。

      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">
      

      Sign up box showing a message that the

      ステップ 9 — ログイン方法の追加

      ログイン方法は、ユーザー情報を取得しそれを使用して何かをするという点でサインアップ機能に似ています。この場合、入力されたメールアドレスを比較して、データベースに存在するかどうかを確認します。そのような場合、ユーザーが渡すパスワードをハッシュし、さらにデータベースのハッシュパスワードを比較して、提供されたパスワードをテストします。両方のハッシュパスワードが一致する場合、ユーザーが正しいパスワードを入力したことが分かります。

      ユーザーがパスワードチェックに合格すると、ユーザーが正しい資格情報を持っていて、Flask-Loginを使用してログインすることができます。login_user を呼び出して、Flask-Loginはユーザーがログインしている間は継続するユーザーセッションを作成します。これにより、ユーザーは保護されたページを見ることができます。

      POSTed データを扱う新しいルートから始めます。ユーザーが正常にログインすると、プロファイルページにリダイレクトします。

      project/auth.py

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

      ユーザーが正しい資格を持っているか確認する必要があります。

      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'))
      

      テンプレート内のブロックに追加しましょう。ユーザーは点滅したメッセージを見ることができます。サインアップフォームと同様に、フォーム上の潜在的なエラーメッセージを追加しましょう。

      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">
      

      ユーザーが正常にログインしていることを伝える機能がありますが、ユーザーをログインするものはありません。ここで、ユーザーセッションを管理するために Flask-Login を取り入れます。

      始める前に、Flask-Login の機能に必要なものがいくつかあります。ユーザーモデルに UserMixin を追加して開始します。UserMixinは、Flask-Loginの属性をモデルに追加します。そのため、Flask-Login は UserMixinと機能します。

      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))
      

      次に、ユーザーのローダーを指定する必要があります。ユーザーローダーは、セッションクッキーに保存されている ID から特定のユーザーを見つける方法を説明します。create_app 関数に、これと Flask-Login の init コードを追加できます。

      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))
      

      最後に、セッションを作成するためにプロファイルページにリダイレクトする前に、login_user 機能を追加します。

      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'))
      

      Flask-Login のセットアップにより、/login ルートを使用できます。すべてが配置されると、プロファイルページが表示されます。

      Profile page with

      ステップ 10 — ページの保護

      あなたの名前が Anthony でない場合、名前が間違っていることがわかります。望まれているのは、データベースに名前を表示するためのプロファイルです。まずページを保護し、ユーザーのデータにアクセスして名前を取得する必要があります。

      Flask-Login を使用している時にページを保護するには、ルートと機能の間にある @login_requried デコレータを追加します。これにより、ログインしていないユーザーがルートを見ることを防ぎます。ユーザーがログインしていない場合、Flask-Login の設定に従ってログインページにリダイレクトされます。

      @login_requiredデコレータでデコレートされたルートにより、関数の内部の current_user オブジェクトを使用する機能があります。この current_user はデータベースからのユーザーを表し、ドット表記によりそのユーザーのすべての属性にアクセスできます。たとえば、current_user.emailcurrent_user.passwordcurrent_user.namecurrent_user.id は、ログイン中のユーザーのためにデータベースに保存された実際の値を戻します。

      現在のユーザー名を使用してテンプレートに送信しましょう。次に、その名前を使用して値を表示します。

      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)
      

      次に、profile.html ファイルに名前の値を表示するためにページを更新します。

      project/templates/profile.html

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

      プロファイルページに移動したら、ユーザー名が表示されることがわかります。

      User welcome page with the name of the currently logged-in user

      最後に、ログアウトビューを更新します。ログアウトのルートで、logout_user 機能を呼び出すことができます。最初からログインしていないユーザーをログアウトするのは意味がないので、@login_required デコレータがあります。

      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'))
      

      ログアウトしてプロファイルページを再び表示した後、エラーメッセージが表示されます。これは、ユーザーがページにアクセスできない場合に Flask-Login がメッセージを点滅させるためです。

      Login page with a message showing that user must log in to access page

      最後に、if文をテンプレートに入れて、ユーザーに関連するリンクのみを表示します。これによって、ログイン前にログインまたはサインアップするか選択することができます。ログインした後、プロファイルに移動またはログアウトできます。

      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>
      

      Home page with the Home, Login, and Sign Up nav at the top of the screen

      これで、アプリケーションに認証を追加することができました。

      まとめ

      Flask-Login と Flask-SQLAlchemy を使用してアプリケーションにログインシステムを構築しました。ユーザーモデルを作成し、さらにユーザー情報を保存することによって、ユーザーを認証する方法を説明しました。そして、フォームからパスワードをハッシュし、データベースに保存されているパスワードを比較することで、ユーザーのパスワードが正しいことを確認しました。最後に、プロファイルページの @login_required デコレータを使用してアプリケーションに認証を追加し、ログインしているユーザーだけがそのページを見ることができるようにしました。

      このチュートリアルで作成したものは、小さなアプリケーションにおいては十分ですが、より多くの機能を最初から望む場合は、Flask-Login ライブラリの上部に構築されている Flask-User または Flask-Security ライブラリを使用することを検討してください。



      Source link

      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