flask中的flask-login

flask中的flask-login

在 Flask 中,用户认证通常是通过使用扩展库(例如 Flask-Login、Flask-HTTPAuth 或 Flask-Security)来实现的。

本文详细地解释下 Flask 中的用户认证。这里是用 Flask-Login 插件为例,这是一个处理用户会话的插件。首先,你需要安装 Flask-Login。你可以使用 pip 来安装:

pip install flask-login

接下来,在你的应用中初始化 Flask-Login:

python 复制代码
from flask_login import LoginManager

login_manager = LoginManager()

然后,在创建 Flask 应用实例之后,你需要初始化 LoginManager:

python 复制代码
app = Flask(__name__)
login_manager.init_app(app)

Flask-Login 要求你实现一个 callback 函数,这个函数接受一个用户 ID,并返回相应的用户对象。这可以通过 user_loader 装饰器来实现:

python 复制代码
from your_model_file import User

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

这里,User 是用户模型,它应该是一个数据库模型,用来存储用户信息。在 Flask 中,常常使用 SQLAlchemy 来管理数据库。一个简单的 User 模型可能如下所示:

python 复制代码
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True)
    password_hash = db.Column(db.String(128))

    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

此处,我们还使用了 Werkzeug 提供的密码散列方法,为了保护用户的密码。

接下来,你需要创建一个登录页面。登录页面需要验证用户输入的用户名和密码:

python 复制代码
from flask import render_template, redirect, url_for, flash
from flask_login import login_user
from your_form_file import LoginForm

@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user is None or not user.check_password(form.password.data):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user)
        return redirect(url_for('index'))
    return render_template('login.html', form=form)

这里的 LoginForm 是一个 Flask-WTF 表单类,用来处理表单数据。

最后,你需要为用户登出设置路由:

python 复制代码
from flask_login import logout_user

@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('index'))

在理解 Flask-Login 的执行流程之前,我们先需要理解几个关键的 Flask-Login 组件:

  1. LoginManager:它是 Flask-Login 的核心,负责管理用户会话。
  2. UserMixin :它为用户类提供默认的实现,如 is_authenticatedis_activeis_anonymousget_id
  3. user_loader:这是一个回调函数,当 Flask-Login 需要知道特定用户的信息时,会调用这个函数。这个函数应该接收一个用户 ID 作为输入,返回相应的用户对象。
  4. login_user:当用户在登录表单中提供了有效的凭证时,应用会调用这个函数,它会在用户会话中记录下该用户已登录。
  5. logout_user:当用户想要退出时,应用会调用这个函数,它会从用户会话中删除登录信息。

现在,我们来看一下 Flask-Login 的工作流程:

  1. 用户访问网站,发送一个请求到服务器。
  2. Flask 应用接收到请求,检查这个请求的会话中是否有用户 ID,如果有,那么 Flask-Login 会用这个 ID 调用 user_loader 回调函数,试图加载这个用户。
  3. 如果 user_loader 回调函数找到了用户,那么这个请求就是已认证的。如果没有找到用户,那么这个请求就是匿名的。
  4. 对于需要用户登录才能访问的视图函数,Flask-Login 会检查用户是否已认证。如果用户已认证,那么就允许访问。如果用户未认证,那么就重定向到登录页面。
  5. 在登录页面,用户会提供登录凭证,比如用户名和密码。服务器验证凭证,如果凭证有效,那么就调用 login_user 函数,记录用户已登录。
  6. 用户在浏览网站时,所有的请求都会带有用户的会话信息,所以服务器能知道是哪个用户发送的请求。
  7. 当用户决定退出时,应用会调用 logout_user 函数,删除用户的会话信息。

这就是 Flask-Login 的基本工作流程。它管理用户的登录状态,并提供一种简便的方式让你能在视图函数中访问当前用户。

补充1

Flask-Login 中的 user_loader 是一个回调函数,其执行时机主要在处理用户的请求时。每当用户发送一个请求到 Flask 应用时,Flask-Login 都会通过在用户会话(session)中存储的用户 ID 来执行 user_loader 函数,以获取对应的用户对象。

具体步骤如下:

  1. 当一个请求到达 Flask 应用时,Flask-Login 会先查看用户的会话中是否有用户 ID 存在。
  2. 如果用户会话中存在 ID,Flask-Login 就会调用 user_loader 函数,并把这个 ID 作为参数传入。
  3. user_loader 函数接收到这个 ID,然后查询数据库(或者其他存储用户数据的地方)找到对应的用户对象,并返回。
  4. Flask-Login 接着将这个用户对象存储在当前请求的上下文中,这样在处理这个请求的后续步骤中,你就可以使用 current_user 变量来访问这个用户对象了。

总的来说,user_loader 的调用是在每个请求开始时进行的,目的是为了从用户的会话中恢复用户对象,这样在处理请求时就可以知道是谁发起的请求,他/她是否有权限访问特定资源等等。

补充2

假设你有一个名为 dashboard 的视图函数,它只允许已认证的用户访问。你可以使用 Flask-Login 提供的 login_required 装饰器来实现这一点:

python 复制代码
from flask_login import login_required

@app.route('/dashboard')
@login_required
def dashboard():
    return render_template('dashboard.html')

如果一个已认证的用户尝试访问这个视图,他们将会正常地看到 dashboard 页面。然而,如果一个未认证的用户(例如,未登录或者会话已过期的用户)尝试访问这个视图,login_required 装饰器将会拦截这个请求,并重定向到登录页面。

你需要在 LoginManager 实例中设置登录视图的名称,以便 Flask-Login 知道未认证的用户应该被重定向到哪里:

python 复制代码
login_manager.login_view = 'login'

这里 'login' 是登录视图函数的端点名。例如,如果你的登录视图函数像下面这样定义:

python 复制代码
@app.route('/login', methods=['GET', 'POST'])
def login():
    # authentication code here
    pass

那么登录视图的端点名就是 'login',所以上面的 login_manager.login_view = 'login' 表示未认证的用户将会被重定向到这个视图。

注意,你的登录视图函数应该处理两种请求方法:'GET' 和 'POST'。'GET' 请求用于显示登录表单,'POST' 请求用于提交表单。

补充3

这里我将为你展示一个简单的 Flask 登录页面的例子,这个例子使用了 Flask-Login 和 Flask-WTF(用于处理表单)。

首先,我们需要创建一个用于处理登录的表单类,如下:

python 复制代码
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired

class LoginForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired()])
    password = PasswordField('Password', validators=[DataRequired()])
    submit = SubmitField('Sign In')

然后,我们需要创建一个处理登录的视图函数,代码如下:

python 复制代码
from flask import render_template, redirect, url_for, flash
from flask_login import login_user
from .forms import LoginForm
from .models import User

@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user is not None and user.check_password(form.password.data):
            login_user(user)
            return redirect(url_for('dashboard'))  #

补充4:用户注册

用户注册通常涉及到以下几个步骤:创建一个用户注册表单,创建一个处理用户提交注册信息的视图函数,以及创建一个用于显示注册表单的模板。

首先,我们需要创建一个用户注册表单,如下:

python 复制代码
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, EqualTo

class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired()])
    password = PasswordField('Password', validators=[DataRequired()])
    confirm_password = PasswordField('Confirm Password', 
                                     validators=[DataRequired(), EqualTo('password')])
    submit = SubmitField('Register')

然后,我们需要创建一个处理用户注册的视图函数,代码如下:

python 复制代码
from flask import render_template, redirect, url_for, flash
from .forms import RegistrationForm
from .models import User, db

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('Congratulations, you are now a registered user!')
        return redirect(url_for('login'))  # 登录页面的路由
    return render_template('register.html', form=form)

在这个视图函数中,当表单通过验证并提交时(form.validate_on_submit()),我们创建一个新的用户对象,并设置其密码(user.set_password(form.password.data))。然后,我们把新用户添加到数据库会话中,并提交会话以将数据写入数据库(db.session.add(user)db.session.commit())。最后,我们显示一个注册成功的消息,并重定向到登录页面。

最后,你需要在你的 'register.html' 模板中添加一个显示注册表单的部分,代码可能如下:

html 复制代码
<form method="POST">
    {{ form.hidden_tag() }}
    <p>
        {{ form.username.label }}<br>
        {{ form.username(size=20) }}
    </p>
    <p>
        {{ form.password.label }}<br>
        {{ form.password(size=20) }}
    </p>
    <p>
        {{ form.confirm_password.label }}<br>
        {{ form.confirm_password(size=20) }}
    </p>
    <p>{{ form.submit() }}</p>
</form>

当用户在注册表单中输入用户名和密码并点击提交时,他们提供的数据将被发送到服务器进行处理。如果所有输入都满足验证规则(例如,两次输入的密码一致),一个新的用户就会被创建,并存储到数据库中。然后用户就会被重定向到登录页面。如果有任何验证失败,用户将被提示重新输入。

补充5:密码找回

密码找回功能的实现通常包括以下步骤:发送包含密码重置链接的电子邮件到用户的注册邮箱,用户点击链接后,被重定向到一个可以设置新密码的页面。

以下是一个简化的实现示例:

  1. 创建一个用于生成和验证密码重置令牌的用户模型方法

首先,在你的用户模型中,添加一个生成令牌的方法和一个验证令牌的方法。通常,可以使用 itsdangerous 库来生成签名的令牌。

python 复制代码
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from flask import current_app

class User(db.Model, UserMixin):
    # ...
    def get_reset_token(self, expires_sec=1800):
        s = Serializer(current_app.config['SECRET_KEY'], expires_sec)
        return s.dumps({'user_id': self.id}).decode('utf-8')

    @staticmethod
    def verify_reset_token(token):
        s = Serializer(current_app.config['SECRET_KEY'])
        try:
            user_id = s.loads(token)['user_id']
        except:
            return None
        return User.query.get(user_id)
  1. 创建一个发送密码重置电子邮件的函数

接下来,你需要创建一个函数,该函数生成一个密码重置令牌,然后发送一封包含密码重置链接的电子邮件到用户的注册邮箱。这个链接应该包含令牌作为查询参数。

你可能会使用 Flask-Mail 插件来发送邮件。

  1. 创建密码重置请求的视图函数

创建一个视图函数来处理密码重置请求,获取用户输入的电子邮件地址,查找关联的用户,如果找到了用户,就调用上面的函数来发送密码重置电子邮件。

  1. 创建处理密码重置链接的视图函数

创建一个视图函数来处理用户点击密码重置链接后的请求。这个视图函数应该从链接的查询参数中获取令牌,然后调用用户模型的 verify_reset_token 方法来验证令牌。如果验证通过,将用户重定向到一个可以输入新密码的表单页面。

  1. 创建设置新密码的视图函数

最后,你需要创建一个视图函数来处理用户提交新密码的请求。这个视图函数应该获取用户的新密码,然后更新用户模型中的密码字段,最后把更新后的用户数据存回数据库。

这个流程需要用户能够接收和发送电子邮件,并且你的应用能够发送电子邮件。这个流程在某些方面可能需要调整以适应你的具体需求,例如邮件服务的选择,以及如何处理邮件发送失败的情况。

相关推荐
API快乐传递者2 分钟前
除了网页标题,还能用爬虫抓取哪些信息?
开发语言·爬虫·python
豌豆花下猫10 分钟前
REST API 已经 25 岁了:它是如何形成的,将来可能会怎样?
后端·python·ai
喔喔咿哈哈22 分钟前
【手撕 Spring】 -- Bean 的创建以及获取
java·后端·spring·面试·开源·github
夏微凉.34 分钟前
【JavaEE进阶】Spring AOP 原理
java·spring boot·后端·spring·java-ee·maven
平头哥在等你2 小时前
Python中的正则表达式教程
python·正则表达式
Best_Me072 小时前
如何在Pycharm的终端里进入自己的环境
ide·python·pycharm
不会编程的懒洋洋2 小时前
Spring Cloud Eureka 服务注册与发现
java·笔记·后端·学习·spring·spring cloud·eureka
NiNg_1_2343 小时前
SpringSecurity入门
后端·spring·springboot·springsecurity
好看资源平台3 小时前
爬虫开发工具与环境搭建——环境配置
爬虫·python
大G哥3 小时前
python 数据类型----可变数据类型
linux·服务器·开发语言·前端·python