基于Flask-Login简单登录和权限控制实践

1. 关于Flask-Login

Flask-Login 是一个为python Flask Web框架设计的扩展,用于管理用户会话(用户登录状态)。它提供了简单的接口来处理用户登录、注销、记住用户等功能,同时确保用户会话的安全性。以下是 Flask-Login 的一些关键特性和功能:

1.1. 主要功能

  1. 用户会话管理:
  • 管理用户登录和注销状态。
  • 自动处理未登录用户访问受保护资源时的重定向。
  1. 记住我功能:
  • 提供“记住我”功能,允许用户在关闭浏览器后仍然保持登录状态。
  • 通过安全的持久化会话(如 cookie)实现。
  1. 用户加载回调:
  • 允许开发者定义一个回调函数,用于从用户 ID 加载用户对象。
  • 支持从数据库或其他存储中动态加载用户。
  1. 登录保护:
  • 提供装饰器 @login_required,用于保护需要用户登录的视图。
  1. 会话安全性:
  • 提供防止会话固定攻击(session fixation)的功能。
  • 支持用户登录后刷新会话 ID。

1.2. 核心组件

  1. LoginManager:
  • 核心管理器,用于配置和管理用户会话。
  • 通常在应用初始化时创建。
  1. User 模型:
    开发者需要定义一个用户模型,该模型必须实现 Flask-Login 所需的接口方法:
  • is_authenticated:是否已认证。
  • is_active:用户是否激活。
  • is_anonymous:是否是匿名用户。
  • get_id():返回用户的唯一标识符(通常是用户 ID)。
  1. 用户加载回调:
  • 通过 LoginManager.user_loader 装饰器定义,用于从用户 ID 加载用户对象。
  • 示例:
from flask_login import UserMixin
 
class User(UserMixin):
    def __init__(self, id):
        self.id = id
 
@login_manager.user_loader
def load_user(user_id):
    # 假设从数据库加载用户
    return User(user_id)
  1. 装饰器:
  • @login_required:保护视图,确保用户已登录。
  • 示例:
from flask import Flask, redirect, url_for
from flask_login import login_required, current_user
 
@app.route('/dashboard')
@login_required
def dashboard():
    return f'Welcome, {
     current_user.id}!'

1.3. 注意事项

  1. 安全性:
  • 确保使用安全的 secret_key。
  • 如果使用“记住我”功能,确保启用安全的 cookie 配置(如 HttpOnly 和 Secure 标志)。
  1. 用户模型:
  • 用户模型必须实现 Flask-Login 所需的接口方法。
  • 推荐使用 UserMixin 提供默认实现。
  1. 错误处理:
    确保处理用户加载失败的情况,例如用户不存在时返回适当的响应。

2. 我的简单登录和权限控制实践

下面是一个简洁的 Flask 登录和权限控制方案,使用 Flask-Login 扩展实现基本功能。

2.1. 安装必要扩展

pip install flask-login

2.2. Flask应用工程目录结构

flask_auth_example/
│
├── app.py                # 主应用文件
├── templates/
│   ├── base.html         # 基础模板
│   ├── index.html        # 首页
│   ├── login.html        # 登录页面
│   ├── register.html     # 注册页面
│   └── admin.html        # 管理员页面
├── requirements.txt      # 依赖文件
└── instance/
    └── database.db       # SQLite数据库
  • 数据库为sqlite3,python以及集成。

2.3. 基础实现代码

下面是一个使用 Flask-Login 实现用户登录和基本权限管理的完整样例。这个示例包括用户登录、登出、注册功能,以及基于角色的权限控制。

2.3.1. 应用代码 (app.py)

from flask import Flask, render_template, redirect, url_for, flash, request
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-here'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///instance/database.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'

# 用户角色
class Role:
    USER = 'user'
    ADMIN = 'admin'

# 用户模型
class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(100), unique=True, nullable=False)
    password_hash = db.Column(db.String(200), nullable=False)
    role = db.Column(db.String(20), default=Role.USER)
    
    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)

# 创建数据库表
with app.app_context():
    db.create_all()

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

# 自定义装饰器检查权限
def admin_required(func):
    @login_required
    def decorated_view(*args, **kwargs):
        if current_user.role != Role.ADMIN:
            flash('您没有访问此页面的权限', 'danger')
            return redirect(url_for('index'))
        return func(*args, **kwargs)
    return decorated_view

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

@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 = request.form.get('remember') == 'on'
        
        user = User.query.filter_by(username=username).first()
        
        if user and user.check_password(password):
            login_user(user, remember=remember)
            flash('登录成功!', 'success')
            next_page =

你可能感兴趣的:(Python,flask,python,后端,flask-login)