Flask 用户认证与授权详细教程(第五阶段)

Flask 用户认证与授权详细教程

在现代Web开发中,用户身份验证和授权是非常重要的要素。这篇教程将会指导你如何使用 Flask 中的 Flask-Login 库来实现用户注册、登录、登出功能,以及如何使用 Flask-Principal 或其他 RBAC(基于角色的访问控制)解决方案来管理用户权限。

一、用户认证

1.1 安装 Flask-Login

在开始之前,我们需要安装 Flask-Login。在命令行中执行以下命令:

pip install Flask-Login

1.2 创建基本的 Flask 应用

首先,创建一个基本的 Flask 应用并配置数据库连接:

import os
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

app = Flask(__name__)
app.secret_key = os.urandom(24)  # 设置随机密钥
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'  # 登录视图

1.3 创建用户模型

创建一个用户模型来存储用户数据。

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(200), nullable=False)

    def __repr__(self):
        return f'<User {self.username}>'

1.4 创建数据库

在应用启动时创建数据库。这可以在其他地方执行,例如在命令行交互中。

with app.app_context():
    db.create_all()

1.5 加载用户回调

实现用户加载回调功能,Flask-Login 会通过用户 ID 加载用户对象。

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

1.6 用户注册

实现用户注册功能:

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        new_user = User(username=username, password=password)
        db.session.add(new_user)
        db.session.commit()
        flash('User registered successfully!')
        return redirect(url_for('login'))
    return render_template('register.html')

创建 register.html 模板:

<!doctype html>
<html>
<head>
    <title>Register</title>
</head>
<body>
    <h1>Register</h1>
    <form method="POST">
        <label for="username">Username:</label>
        <input type="text" name="username" required>
        <br>
        <label for="password">Password:</label>
        <input type="password" name="password" required>
        <br>
        <input type="submit" value="Register">
    </form>
</body>
</html>

1.7 用户登录

实现用户登录功能:

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        user = User.query.filter_by(username=username).first()
        if user and user.password == password:
            login_user(user)
            return redirect(url_for('profile'))
        flash('Invalid username or password')
    return render_template('login.html')

创建 login.html 模板:

<!doctype html>
<html>
<head>
    <title>Login</title>
</head>
<body>
    <h1>Login</h1>
    <form method="POST">
        <label for="username">Username:</label>
        <input type="text" name="username" required>
        <br>
        <label for="password">Password:</label>
        <input type="password" name="password" required>
        <br>
        <input type="submit" value="Login">
    </form>
</body>
</html>

1.8 用户个人资料

创建用户个人资料页面,只有已登录用户可以访问:

@app.route('/profile')
@login_required
def profile():
    return f'Hello, {current_user.username}! <a href="/logout">Logout</a>'

1.9 用户登出

实现用户登出功能:

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

1.10 完整代码示例

以下是整合所有代码的完整示例:

import os
from flask import Flask, request, redirect, url_for, render_template, flash
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user

app = Flask(__name__)
app.secret_key = os.urandom(24)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(200), nullable=False)

    def __repr__(self):
        return f'<User {self.username}>'

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

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        new_user = User(username=username, password=password)
        db.session.add(new_user)
        db.session.commit()
        flash('User registered successfully!')
        return redirect(url_for('login'))
    return render_template('register.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        user = User.query.filter_by(username=username).first()
        if user and user.password == password:
            login_user(user)
            return redirect(url_for('profile'))
        flash('Invalid username or password')
    return render_template('login.html')

@app.route('/profile')
@login_required
def profile():
    return f'Hello, {current_user.username}! <a href="/logout">Logout</a>'

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

if __name__ == '__main__':
    with app.app_context():
        db.create_all()  # 创建数据库表
    app.run(debug=True)

二、用户权限管理

2.1 安装 Flask-Principal

接下来,我们将使用 Flask-Principal 来实现基于角色的权限控制。首先安装 Flask-Principal:

pip install Flask-Principal

2.2 配置权限

在应用中配置 Flask-Principal

from flask_principal import Principal, Permission, RoleNeed

# 初始化 Flask-Principal
principals = Principal(app)

# 定义角色权限
admin_permission = Permission(RoleNeed('admin'))
editor_permission = Permission(RoleNeed('editor'))

2.3 扩展用户模型

在用户模型中,加入角色属性:

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(200), nullable=False)
    roles = db.Column(db.String(200), default='user')  # 角色字段

    def has_role(self, role):
        return role in self.roles.split(',')

2.4角色分配

在用户注册或通过管理面板创建用户时可以分配角色:

def register_user(username, password, roles='user'):
    new_user = User(username=username, password=password, roles=roles)
    db.session.add(new_user)
    db.session.commit()

2.5 权限检查

在需要控制权限的视图函数前进行权限检查:

@app.route('/admin')
@login_required
@admin_permission.require(http_exception=403)
def admin_panel():
    return 'Welcome to the admin panel!'

@app.route('/editor')
@login_required
@editor_permission.require(http_exception=403)
def editor_panel():
    return 'Welcome to the editor panel!'

2.6 完整示例整合

将权限控制整合到完整示例中:

import os
from flask import Flask, request, redirect, url_for, render_template, flash
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from flask_principal import Principal, Permission, RoleNeed

app = Flask(__name__)
app.secret_key = os.urandom(24)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
principals = Principal(app)

admin_permission = Permission(RoleNeed('admin'))
editor_permission = Permission(RoleNeed('editor'))

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(200), nullable=False)
    roles = db.Column(db.String(200), default='user')

    def has_role(self, role):
        return role in self.roles.split(',')

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

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        roles = request.form.get('roles', 'user')  # 默认用户角色
        new_user = User(username=username, password=password, roles=roles)
        db.session.add(new_user)
        db.session.commit()
        flash('User registered successfully!')
        return redirect(url_for('login'))
    return render_template('register.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        user = User.query.filter_by(username=username).first()
        if user and user.password == password:
            login_user(user)
            return redirect(url_for('profile'))
        flash('Invalid username or password')
    return render_template('login.html')

@app.route('/profile')
@login_required
def profile():
    return f'Hello, {current_user.username}! <a href="/logout">Logout</a>'

@app.route('/admin')
@login_required
@admin_permission.require(http_exception=403)
def admin_panel():
    return 'Welcome to the admin panel!'

@app.route('/editor')
@login_required
@editor_permission.require(http_exception=403)
def editor_panel():
    return 'Welcome to the editor panel!'

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

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(debug=True)

2.7 完成用户角色管理

在注册页面添加角色选项来允许分配角色:

<label for="roles">Role:</label>
<select name="roles">
    <option value="user">User</option>
    <option value="editor">Editor</option>
    <option value="admin">Admin</option>
</select>

三、总结

本教程介绍了如何在 Flask 应用中实现用户认证和授权。使用 Flask-Login 来处理用户的注册、登录、登出,以及如何使用 Flask-Principal 实现基于角色的权限控制。在实际应用中,您可以根据需求进一步扩展和细化这些功能。

通过该教程,您应该获得了对 Flask 中用户身份验证和权限管理的基本理解,以及如何实现这些功能的能力。希望这些示例和代码能为您搭建安全的 Flask 应用提供帮助!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值