flask-login_如何使用Flask-Login向您的应用程序添加身份验证

本文详细介绍了如何使用Flask-Login库为Flask应用添加身份验证功能,包括创建用户会话、哈希密码、创建用户模型、配置数据库、创建注册和登录表单、保护受保护页面等步骤,以及测试和错误处理。通过这个教程,你可以为你的Web应用实现用户登录和访问控制功能。
摘要由CSDN通过智能技术生成

flask-login

介绍 (Introduction)

Allowing users to log in to your app is one of the most common features you’ll add to your web application. This article will cover how to add authentication to your Flask app with the Flask-Login package.

允许用户登录到您的应用程序是您将添加到Web应用程序的最常见功能之一。 本文将介绍如何使用Flask-Login软件包向您的Flask应用添加身份验证。

We’re going to build some sign-up and login pages that allow users to log in and access protected pages that users who aren’t logged in can’t 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

    使用Flask-Login库进行会话管理
  • Use the built-in Flask utility for hashing passwords

    使用内置的Flask实用程序对密码进行哈希处理
  • Add protected pages to our app for logged in users only

    将受保护的页面添加到我们的应用中,仅适用于登录用户
  • Use Flask-SQLAlchemy to create a user model

    使用Flask-SQLAlchemy创建用户模型
  • 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

    发生错误时将Flash错误消息返回给用户
  • Use information from the user’s account to display on the profile page

    使用来自用户帐户的信息显示在配置文件页面上

The source code for this project is available on GitHub.

项目源代码可在GitHub上找到

先决条件 (Prerequisites)

To complete this tutorial, you will need the following:

要完成本教程,您将需要以下内容:

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 for our regular routes, which include the index and the protected profile page. In a real app, you can break down the functionality in any way you like, but the solution covered here will work well for this tutorial.

我们的应用程序将使用带有蓝图的Flask应用程序工厂模式。 我们将拥有一个处理所有与auth相关的蓝图,并且将为我们的常规路由提供另一个蓝图,其中包括索引和受保护的个人资料页面。 在真实的应用程序中,您可以按自己喜欢的任何方式分解功能,但是此处介绍的解决方案对于本教程来说效果很好。

Here is a diagram to provide a sense of what your project’s file structure will look like once you have completed the 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

As we progress through the tutorial, we will create these directories and files.

在学习本教程的过程中,我们将创建这些目录和文件。

第1步-安装软件包 (Step 1 — Installing Packages)

There are three main packages we need for our project:

我们的项目需要三个主要软件包:

  • Flask

    烧瓶
  • Flask-Login: to handle the user sessions after authentication

    Flask-Login:认证后处理用户会话
  • Flask-SQLAlchemy: to represent the user model and interface with our database

    Flask-SQLAlchemy:表示用户模型和与我们的数据库的接口

We’ll be using SQLite to avoid having to install any extra dependencies for the database.

我们将使用SQLite来避免必须为数据库安装任何其他依赖项。

First, we will start with creating the project directory:

首先,我们将从创建项目目录开始:

  • mkdir flask_auth_app

    mkdir flask_auth_app

Next, we need to navigate to the project directory:

接下来,我们需要导航到项目目录:

  • cd flask_auth_app

    cd flask_auth_app

You will want to create a Python environment if you don’t have one. Depending on how Python was installed on your machine, your commands will look similar to:

如果您没有Python环境,则需要创建它。 根据计算机上安装Python的方式,您的命令将类似于:

  • python3 -m venv auth

    python3 -m venv 身份验证

  • source auth/bin/activate

    源身份验证 / bin / activate

Note: You can consult the tutorial relevant to your local environment for setting up venv.

注意:您可以参考与您的本地环境有关的教程来设置venv

Run the following commands from your virtual environment to install the needed packages:

在虚拟环境中运行以下命令以安装所需的软件包:

  • pip install flask flask-sqlalchemy flask-login

    pip安装烧瓶flask-sqlalchemy flask-login

Now that you’ve installed the packages, you are ready to create the main app file.

既然已经安装了软件包,就可以创建主应用程序文件了。

第2步-创建主应用程序文件 (Step 2 — Creating the Main App File)

Let’s start by creating a project directory:

让我们从创建project目录开始:

  • mkdir project

    mkdir项目

The first file we will work on will be the __init__.py file for our project:

我们将处理的第一个文件是项目的__init__.py文件:

  • nano project/__init__.py

    纳米项目/__init__.py

This file 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. We need to initialize SQLAlchemy, set some configuration values, and register our blueprints here.

该文件将具有创建我们的应用程序的功能,该应用程序将初始化数据库并注册我们的蓝图。 目前,这不会做太多,但是我们其余应用程序将需要它。 我们需要初始化SQLAlchemy,设置一些配置值,然后在此处注册我们的蓝图。

project/__init__.py
项目/__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

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

现在我们有了主应用程序文件,我们可以开始添加路线了。

第3步-添加路线 (Step 3 — Adding Routes)

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

对于我们的路线,我们将使用两个蓝图。 对于我们的主要蓝图,登录后将有一个主页( / )和个人资料页面( /profile )。如果用户尝试不登录而访问个人资料页面,则将其发送到登录名路线。

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

对于我们的auth蓝图,我们将具有检索登录页面( /login )和注册页面( /sign-up )的路由。 我们还将提供用于处理来自这两个路由的POST请求的路由。 最后,我们将有一个注销路由( /logout )来注销活动用户。

For the time being, we will define login, signup, and logout with simple returns. We will revisit them at a later step and update them with desired functionality.

目前,我们将使用简单的返回值定义loginsignuplogout 。 我们将在以后的步骤中对它们进行重新访问,并以所需的功能对其进行更新。

First, create main.py for your main_blueprint:

首先,创建main.py为您main_blueprint

  • nano project/main.py

    纳米项目/main.py
project/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'

Next, create auth.py for your auth_blueprint:

接下来,创建auth.py为您auth_blueprint

  • nano project/auth.py

    纳米项目/ auth.py
project/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'

In a terminal, you can set the FLASK_APP and FLASK_DEBUG values:

在终端中,可以设置FLASK_APPFLASK_DEBUG值:

  • export FLASK_APP=project

    导出FLASK_APP =项目
  • export FLASK_DEBUG=1

    出口FLASK_DEBUG = 1

The FLASK_APP environment variable instructs Flask how to load the app. It should point to where create_app is located. For our needs, we will be pointing to the project directory.

FLASK_APP环境变量指示Flask如何加载应用程序。 它应该指向create_app所在的位置。 对于我们的需求,我们将指向project目录。

The FLASK_DEBUG environment variable is enabled by setting it to 1. This will enable a debugger that will display application errors in the browser.

通过将FLASK_DEBUG环境变量设置为1来启用它。 这将启用调试器,该调试器将在浏览器中显示应用程序错误。

Ensure that you are in the flask_auth_app directory and then run the project:

确保您位于flask_auth_app目录中,然后运行项目:

  • flask run

    烧瓶运行

Now, in a web browser, you should be able to navigate to the five possible URLs and see the text returned that was defined in auth.py and main.py.

现在,在Web浏览器中,您应该能够导航到五个可能的URL,并查看在auth.pymain.py定义的返回的文本。

For example, visiting localhost:5000/profile displays: Profile:

例如,访问localhost:5000/profile显示: Profile

Now that we have verified that our routes are behaving as expected, we can move on to creating templates.

既然我们已经验证了路由的行为符合预期,那么我们就可以继续创建模板了。

第4步-创建模板 (Step 4 — Creating Templates)

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

    index.html
  • profile.html

    profile.html
  • login.html

    login.html
  • signup.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.

我们还将有一个基本模板,该模板将具有每个页面共有的代码。 在这种情况下,基本模板将具有导航链接和页面的总体布局。 现在创建它们。

First, create a templates directory under the project directory:

首先,在project目录下创建一个templates目录:

  • mkdir -p project/templates

    mkdir -p项目/模板

Then create base.html:

然后创建base.html

  • nano project/templates/base.html

    纳米项目/templates/base.html

Next, add the following code to the base.html file:

接下来,将以下代码添加到base.html文件:

project/templates/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>

This code will create a series of menu links to each page of the application and an area where content will appear.

此代码将创建一系列菜单链接,这些菜单链接指向应用程序的每个页面以及将显示内容的区域。

Note: Behind the scenes, we are using Bulma to handle styling and layout. For a deeper dive into Bulma, consider reading the official Bulma documentation.

注意:在幕后,我们使用Bulma处理样式和布局。 要深入了解布尔玛,请考虑阅读布尔玛官方文档

Next, create templates/index.html:

接下来,创建templates/index.html

  • nano project/templates/index.html

    纳米项目/templates/index.html

Add the following code to the newly create file to add content to the page:

将以下代码添加到新创建的文件中以向页面添加内容:

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

This code will create a basic index page with a title and subtitle.

此代码将创建带有标题和字幕的基本索引页。

Next, create templates/login.html:

接下来,创建templates/login.html

  • nano project/templates/login.html

    纳米项目/模板/login.html

This code generates a login page with fields for Email and Password. There is also a checkbox to “remember” a logged in session.

此代码将生成一个登录页面,其中包含“ 电子邮件”和“ 密码”字段。 还有一个复选框可以“记住”已登录的会话。

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

Next, create templates/signup.html:

接下来,创建templates/signup.html

  • nano project/templates/signup.html

    纳米项目/templates/signup.html

Add the following code to create a sign-up page with fields for email, name, and password:

添加以下代码以创建包含电子邮件,名称和密码字段的注册页面:

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

Next, create templates/profile.html:

接下来,创建templates/profile.html

  • nano project/templates/profile.html

    纳米项目/templates/profile.html

Add this code to create a simple page with a title that is hardcoded to welcome Anthony:

添加此代码以创建一个简单的页面,其标题经过硬编码以欢迎Anthony

project/templates/profile.html
project / templates / profile.html
{% extends "base.html" %}

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

Later, we will add code to dynamically greet any user.

稍后,我们将添加代码以动态地问候任何用户。

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.

一旦添加了模板,我们就可以在必须返回模板而不是文本的每条路线中更新return语句。

Next, update main.py by modifying the import line and the routes for index and profile:

接下来,通过修改导入行以及indexprofile的路由来更新main.py

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

Now you will update auth.py by modifying the import line and routes for login and signup:

现在,您将通过修改用于loginsignup的导入行和路由来更新auth.py

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

Once you’ve made these changes, here is what the sign-up page looks like if you navigate to /sign-up:

进行这些更改后,如果导航到/sign-up则注册页面如下所示:

You should be able to see the pages for /, /login, and /profile as well.

您还应该能够看到//login/profile的页面。

We’ll leave /logout alone for now because it won’t display a template when it’s done.

我们暂时将/logout保留下来,因为完成后它不会显示模板。

第5步-创建用户模型 (Step 5 — Creating User Models)

Our user model represents what it means for our app to have a user. We’ll have fields for an email address, password, and name. 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 that then translate to tables in a database. The attributes of those classes then turn into columns for those tables.

在Flask-SQLAlchemy中创建的模型由类表示,这些类随后转换为数据库中的表。 这些类的属性然后变成这些表的列。

Let’s go ahead and create that user model:

让我们继续创建该用户模型:

  • nano project/models.py

    纳米项目/models.py

This code creates a user model with columns for an id, email, password, and name:

此代码创建一个用户模型,其中包含idemailpasswordname

project/models.py
项目/模型.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))

Now that you’ve created a user model, you can move on to configuring your database.

创建用户模型后,就可以继续配置数据库了。

第6步—配置数据库 (Step 6 — Configuring the Database)

As stated in the Prerequisites, 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 in the Python REPL.

如先决条件中所述,我们将使用SQLite数据库。 我们可以自己创建一个SQLite数据库,但让我们让Flask-SQLAlchemy来完成它。 我们已经在__init__.py文件中指定了数据库的路径,因此我们只需要告诉Flask-SQLAlchemy在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. Ensure that you are still in the virtual environment and in the flask_auth_app directory.

如果您停止应用程序并打开Python REPL,我们可以使用db对象上的create_all方法创建数据库。 确保您仍在虚拟环境中和flask_auth_app目录中。

  • from project import db, create_app

    从项目导入数据库create_app
  • db.create_all(app=create_app()) # pass the create_app result so Flask-SQLAlchemy gets the configuration.

    db.create_all(app = create_app())#传递create_app结果,以便Flask-SQLAlchemy获取配置。

Note: If using the Python interpreter is new to you, you can consult the official documentation.

注意:如果您不熟悉使用Python解释器,则可以查阅官方文档

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

现在,您将在项目目录中看到一个db.sqlite文件。 该数据库中将包含我们的用户表。

步骤7 —设置授权功能 (Step 7 — Setting Up the Authorization Function)

For our sign up function, we’re going to take the data the user types into the form and add it to our database. 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 POST form data. In this function, we will gather the data passed from the user first.

让我们开始添加第二个函数来处理POST表单数据。 在此功能中,我们将首先收集从用户传递来的数据。

Create the function and add a redirect to the bottom. This will provide a user experience of a successful signup and being directed to the Login Page.

创建函数并将重定向添加到底部。 这将为用户提供成功注册并定向到登录页面的体验。

Update auth.py by modifying the import line and implementing signup_post:

更新auth.py通过修改进口线和实施signup_post

project/auth.py
项目/ 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'))

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.

首先,我们必须使用request对象获取表单数据。

Continue to update auth.py by adding imports and implementing signup_post:

继续更新auth.py通过增加进口和实施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'))

Note: Storing passwords in plaintext is considered a poor security practice. You will generally want to utilize a complex hashing algorithm and a password salt to keep passwords secure.

注意:以纯文本格式存储密码被认为是不安全的做法。 通常,您将需要利用复杂的哈希算法和密码盐来确保密码的安全。

第8步-测试注册方法 (Step 8 — Testing the Sign Up Method)

Now that we have the sign-up 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 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.

我们可以添加代码以使用户知道电子邮件已经存在,并告诉他们转到登录页面。 通过调用flash函数,我们将向下一个请求发送一条消息,在本例中为重定向。 然后,我们登录的页面将可以访问模板中的该消息。

First, we add the flash before we redirect back to our sign-up page.

首先,我们添加flash然后重定向回我们的注册页面。

project/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: # 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'))

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.

要在模板中获取刷新的消息,我们可以将此代码添加到表单上方。 这将在表格正上方显示消息。

project/templates/signup.html
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">

步骤9 —添加登录方法 (Step 9 — Adding the Login Method)

The login method is similar to the sign-up 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 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.

用户通过密码检查后,我们知道他们具有正确的凭据,我们可以使用Flask-Login登录。 通过调用login_user ,Flask-Login将为该用户创建一个会话,该会话将在用户保持登录状态时保持不变,从而使该用户可以查看受保护的页面。

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:

我们可以从处理POST数据的新路线开始。 用户成功登录后,我们将重定向到个人资料页面:

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

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

现在,我们需要验证用户是否具有正确的凭据:

project/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()

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

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

让我们在模板中添加块,以便用户可以看到闪烁的消息。 像注册表单一样,让我们​​直接在表单上方添加潜在的错误消息:

project/templates/login.html
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">

We now have the ability to say a user has been logged in successfully, but there is nothing to log the user into. This is where we bring in Flask-Login to manage user sessions.

现在,我们可以说用户已经成功登录,但是没有什么可以登录的。 这是我们引入Flask-Login来管理用户会话的地方。

Before we get started, we need a few things for Flask-Login to work. Start by adding the UserMixin to your User model. The UserMixin will add Flask-Login attributes to the model so that Flask-Login will be able to work with it.

在开始之前,我们需要做一些事情来使Flask-Login正常工作。 首先将UserMixin添加到您的用户模型。 UserMixin会将Flask-Login属性添加到模型,以便Flask-Login可以使用它。

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

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 init code for Flask-Login:

然后,我们需要指定我们的用户加载器。 用户加载器告诉Flask-Login如何从存储在其会话cookie中的ID中查找特定用户。 我们可以将其与Flask-Login的init代码一起添加到create_app函数中:

project/__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):
        # 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))

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

最后,我们可以在重定向到概要文件页面以创建会话之前添加login_user函数:

project/auth.py
项目/ 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'))

With Flask-Login setup, we can use the /login route. When everything is in place, you will see the profile page.

通过Flask-Login设置,我们可以使用/login路由。 一切就绪后,您将看到个人资料页面。

第10步-保护页面 (Step 10 — Protecting Pages)

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.

如果您的名字也不是Anthony ,那么您会发现您的名字是错误的。 我们想要的是配置文件以在数据库中显示名称。 因此,首先,我们需要保护页面,然后访问用户数据以获取名称。

To protect a page when using Flask-Login, 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.

为了在使用Flask-Login时保护页面,我们在路由和函数之间添加了@login_requried装饰器。 这样可以防止未登录的用户看到路由。 如果用户未登录,则根据Flask-Login配置,该用户将被重定向到登录页面。

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, and current_user.name, and current_user.id will return the actual values stored in the database for the logged-in user.

通过使用@login_required装饰器装饰的路由,我们可以在函数内部使用current_user对象。 这个current_user代表数据库中的用户,我们可以使用点符号来访问该用户的所有属性。 例如, current_user.emailcurrent_user.passwordcurrent_user.name以及current_user.id将为登录用户返回存储在数据库中的实际值。

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

让我们使用当前用户的名称,并将其发送到模板。 然后,我们将使用该名称并显示其值。

project/main.py
项目/ 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)

Then in the profile.html file, update the page to display the name value:

然后在profile.html文件中,更新页面以显示name值:

project/templates/profile.html
project / 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 the 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 logout a user who isn’t logged in to begin with.

我们可以做的最后一件事是更新注销视图。 我们可以在logout_user路径中调用logout_user函数。 我们有@login_required装饰器,因为注销没有登录的用户没有任何意义。

project/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.

注销并尝试再次查看配置文件页面后,我们会看到一条错误消息。 这是因为当不允许用户访问页面时,Flask登录会为我们闪烁一条消息。

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 logs in, they will have the option to log in or sign up. After they have logged in, they can go to their profile or log out:

我们可以做的最后一件事是在模板中放置if语句,以仅显示与用户相关的链接。 因此,在用户登录之前,他们可以选择登录或注册。 登录后,他们可以转到其个人资料或注销:

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>

With that, you have successfully built your app with authentication.

这样,您就可以使用身份验证成功构建您的应用程序。

结论 (Conclusion)

We’ve used Flask-Login and Flask-SQLAlchemy to build a login system for our app. We covered how to authenticate a user by first creating a user model and storing the user information. 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.

我们已经使用Flask-Login和Flask-SQLAlchemy为我们的应用程序构建了一个登录系统。 我们首先通过创建用户模型并存储用户信息介绍了如何对用户进行身份验证。 然后,我们必须通过对表单中的密码进行哈希处理并将其与数据库中存储的密码进行比较,以验证用户密码是否正确。 最后,我们通过在个人资料页面上使用@login_required装饰器为我们的应用添加了授权,以便只有登录的用户才能看到该页面。

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 built on top of the Flask-Login library.

我们在本教程中创建的内容对于较小的应用程序已经足够了,但是如果您希望从一开始就拥有更多功能,则可以考虑使用Flask-User或Flask-Security库,它们都基于Flask-Login库。

翻译自: https://www.digitalocean.com/community/tutorials/how-to-add-authentication-to-your-app-with-flask-login

flask-login

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值