目录
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 应用提供帮助!