文章目录
flask-login 是 Flask 生态中用于处理用户认证的核心扩展库,专注于管理用户会话(登录、注销、会话维持等),简化了用户认证流程,避免开发者重复实现复杂的会话管理逻辑。它不直接处理用户数据库验证(如密码校验),而是专注于会话生命周期管理,可与任意用户存储方案(如 SQL 数据库、NoSQL、LDAP 等)配合使用。
一、flask-login 核心功能
- 用户会话管理:自动处理用户登录状态的创建、维持和销毁
- 登录状态验证:提供装饰器保护路由,仅允许登录用户访问
- "记住我"功能:支持长期会话,即使浏览器关闭后仍能保持登录状态
- 用户加载机制:通过回调函数从会话中加载用户对象
- 安全特性:内置防会话固定攻击、自动处理用户会话过期等
二、核心概念与依赖
- 用户模型(User Model):必须实现特定属性/方法(或继承
UserMixin简化实现) - 用户加载器(User Loader):回调函数,用于从用户 ID 加载用户对象
- 登录管理器(LoginManager):核心对象,协调认证流程
- 依赖:需安装
flask和flask-login(Python 3.6+ 支持)
三、使用步骤与代码示例
步骤 1:安装依赖
pip install flask flask-login
步骤 2:初始化应用与登录管理器
首先创建 Flask 应用,初始化 LoginManager,并配置必要参数(如密钥)。
from flask import Flask, render_template, redirect, url_for, request, flash
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
# 初始化Flask应用
app = Flask(__name__)
# 配置密钥(用于会话加密,生产环境需使用复杂随机值)
app.config['SECRET_KEY'] = 'your-secret-key-here-keep-it-safe'
# 初始化登录管理器
login_manager = LoginManager(app)
# 设置登录页面路由(未登录用户访问受保护路由时跳转至此)
login_manager.login_view = 'login'
# 登录提示消息
login_manager.login_message = '请先登录以访问该页面'
login_manager.login_message_category = 'info'
步骤 3:定义用户模型
用户模型需实现 flask-login 要求的 4 个属性/方法(或直接继承 UserMixin 简化):
is_authenticated:是否已认证(布尔值)is_active:账户是否激活(布尔值)is_anonymous:是否为匿名用户(布尔值)get_id():返回用户唯一标识符(字符串)
# 示例:使用内存字典模拟用户数据库
users = {
'user1': {'password': 'pass123', 'id': 1, 'name': '张三'},
'user2': {'password': 'pass456', 'id': 2, 'name': '李四'}
}
# 定义用户类(继承UserMixin简化实现)
class User(UserMixin):
def __init__(self, user_id, username, name):
self.id = user_id # 唯一标识(必须)
self.username = username
self.name = name
# 实现用户加载器(核心!用于从会话中加载用户)
@login_manager.user_loader
def load_user(user_id):
# 根据用户ID从数据库/存储中查询用户
# 这里从模拟字典中查询
for username, user_data in users.items():
if user_data['id'] == int(user_id):
return User(
user_id=user_data['id'],
username=username,
name=user_data['name']
)
return None # 未找到用户返回None
步骤 4:实现登录与注销视图
- 登录:验证用户凭据(用户名/密码),通过
login_user()函数创建会话 - 注销:通过
logout_user()函数销毁会话
# 登录视图
@app.route('/login', methods=['GET', 'POST'])
def login():
# 如果已登录,直接跳转到首页
if current_user.is_authenticated:
return redirect(url_for('index'))
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
remember = 'remember' in request.form # "记住我"复选框
# 验证用户(实际应用中应查询数据库)
user_data = users.get(username)
if not user_data or user_data['password'] != password:
flash('用户名或密码错误', 'danger')
return redirect(url_for('login'))
# 创建用户对象
user = User(
user_id=user_data['id'],
username=username,
name=user_data['name']
)
# 登录用户(创建会话)
# remember=True:启用"记住我"功能(会话有效期更长)
login_user(user, remember=remember)
# 如果有跳转页面(如访问受保护路由被拦截后跳转登录),则跳转到该页面
next_page = request.args.get('next')
return redirect(next_page or url_for('index'))
# GET请求:显示登录表单
return render_template('login.html')
# 注销视图
@app.route('/logout')
@login_required # 仅登录用户可访问
def logout():
logout_user() # 销毁会话
flash('已成功注销', 'info')
return redirect(url_for('login'))
步骤 5:创建受保护路由
使用 @login_required 装饰器保护路由,未登录用户访问时会自动跳转到登录页。
# 首页(公开访问)
@app.route('/')
def index():
return render_template('index.html')
# 个人中心(仅登录用户可访问)
@app.route('/profile')
@login_required # 保护路由
def profile():
# current_user:全局变量,自动获取当前登录用户对象
return render_template('profile.html', user=current_user)
# 管理员页面(示例:更严格的权限控制)
@app.route('/admin')
@login_required
def admin():
# 假设只有id=1的用户是管理员
if current_user.id != 1:
flash('没有管理员权限', 'danger')
return redirect(url_for('index'))
return render_template('admin.html')
步骤 6:创建模板文件
需要简单的 HTML 模板配合(放在 templates 文件夹下):
login.html(登录表单)
<!DOCTYPE html>
<html>
<head>
<title>登录</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-5" style="max-width: 500px;">
<h2>用户登录</h2>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
<form method="post">
<div class="mb-3">
<label for="username" class="form-label">用户名</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">密码</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="remember" name="remember">
<label class="form-check-label" for="remember">记住我</label>
</div>
<button type="submit" class="btn btn-primary">登录</button>
</form>
</div>
</body>
</html>
profile.html(个人中心)
<!DOCTYPE html>
<html>
<head>
<title>个人中心</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-5">
<h2>个人中心</h2>
<p>登录用户:{{ user.name }}({{ user.username }})</p>
<p>用户ID:{{ user.id }}</p>
<a href="{{ url_for('logout') }}" class="btn btn-danger">注销</a>
<a href="{{ url_for('index') }}" class="btn btn-secondary">返回首页</a>
</div>
</body>
</html>
步骤 7:运行应用
if __name__ == '__main__':
app.run(debug=True) # 开发环境使用debug模式
四、关键知识点解析
-
current_user全局变量:
由flask-login提供,在任意视图或模板中可直接访问,自动指向当前登录用户(未登录时为匿名用户)。 -
用户加载器(
user_loader):
核心回调函数,flask-login会在每次请求时通过它从用户 ID 加载用户对象,必须实现(否则无法维持登录状态)。 -
"记住我"功能:
通过login_user(user, remember=True)启用,会话有效期默认为 365 天(可通过REMEMBER_COOKIE_DURATION配置)。 -
会话安全:
- 自动生成安全的会话 ID
- 支持配置会话过期时间(
PERMANENT_SESSION_LIFETIME) - 防会话固定攻击(登录时自动刷新会话 ID)
五、扩展与最佳实践
-
结合数据库:实际应用中应使用 SQLAlchemy 等 ORM 管理用户数据,而非内存字典。
示例(SQLAlchemy 用户模型):from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy(app) class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(50), unique=True, nullable=False) password = db.Column(db.String(100), nullable=False) # 存储加密后的密码 name = db.Column(db.String(100)) -
密码安全:永远不要明文存储密码,应使用
werkzeug.security加密:from werkzeug.security import generate_password_hash, check_password_hash # 存储密码时加密 hashed_password = generate_password_hash('user_password', method='pbkdf2:sha256') # 验证密码时 if check_password_hash(user.hashed_password, input_password): # 密码正确 -
自定义匿名用户:通过
login_manager.anonymous_user配置自定义匿名用户类。 -
会话配置:在生产环境中调整会话相关配置:
app.config['PERMANENT_SESSION_LIFETIME'] = 3600 # 会话有效期(秒) app.config['REMEMBER_COOKIE_DURATION'] = 30 * 24 * 3600 # "记住我"有效期(30天) app.config['SESSION_COOKIE_SECURE'] = True # 仅通过HTTPS传输cookie
总结
flask-login 是 Flask 认证的事实标准库,它剥离了复杂的会话管理细节,让开发者专注于业务逻辑。核心流程为:定义用户模型 → 实现用户加载器 → 处理登录/注销 → 保护路由。配合密码加密和数据库存储,可构建安全可靠的用户认证系统。
2285

被折叠的 条评论
为什么被折叠?



