在 Web 应用中,用户认证(Authentication)和权限管理(Authorization)是至关重要的功能。Flask 提供了多种方式来实现用户身份验证,包括 Flask-Login 进行用户会话管理,Flask-WTF 处理表单,以及 Flask-Bcrypt 进行密码加密。
本章内容:
- Flask-Login 介绍
- Flask-WTF 处理用户注册
- Flask-Bcrypt 进行密码加密
- 用户登录与会话管理
- 访问控制与权限管理
- 基于角色的权限控制(RBAC)
- API 认证(JWT)
7.1 安装所需扩展
pip install flask-login flask-wtf flask-bcrypt flask-sqlalchemy
7.2 配置 Flask-Login
在 app.py 里初始化 Flask-Login:
python
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login' # 指定未登录时跳转的视图
login_manager.login_message = "请先登录才能访问该页面!"
7.3 定义用户模型
python
from flask_login import UserMixin
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
def __repr__(self):
return f"User('{self.username}', '{self.email}')"
说明:
- UserMixin 提供 is_authenticated, is_active, is_anonymous, get_id() 等方法。
7.4 加载用户
Flask-Login 需要一个用户加载函数,在 app.py 中添加:
python
from flask_login import LoginManager
from models import User
@login_manager.user_loaderdef load_user(user_id):
return User.query.get(int(user_id))
7.5 用户注册
7.5.1 创建注册表单
python
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Email, EqualTo
class RegistrationForm(FlaskForm):
username = StringField('用户名', validators=[DataRequired()])
email = StringField('邮箱', validators=[DataRequired(), Email()])
password = PasswordField('密码', validators=[DataRequired()])
confirm_password = PasswordField('确认密码', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('注册')
7.5.2 处理用户注册
在 routes.py 里添加视图:
python
from flask import render_template, redirect, flash, url_for
from app import app, db
from models import User
from forms import RegistrationForm
from flask_bcrypt import Bcrypt
bcrypt = Bcrypt(app)
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
user = User(username=form.username.data, email=form.email.data, password=hashed_password)
db.session.add(user)
db.session.commit()
flash('账号注册成功!请登录', 'success')
return redirect(url_for('login'))
return render_template('register.html', form=form)
7.5.3 创建register.html
html
<form method="POST">
{{ form.hidden_tag() }}
<p>{{ form.username.label }} {{ form.username }}</p>
<p>{{ form.email.label }} {{ form.email }}</p>
<p>{{ form.password.label }} {{ form.password }}</p>
<p>{{ form.confirm_password.label }} {{ form.confirm_password }}</p>
<p>{{ form.submit }}</p>
</form>
7.6 用户登录与登出
7.6.1 创建登录表单
python
from wtforms.validators import Length
class LoginForm(FlaskForm):
email = StringField('邮箱', validators=[DataRequired(), Email()])
password = PasswordField('密码', validators=[DataRequired(), Length(min=6, max=20)])
submit = SubmitField('登录')
7.6.2 处理用户登录
python
from flask_login import login_user
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user and bcrypt.check_password_hash(user.password, form.password.data):
login_user(user)
flash('登录成功!', 'success')
return redirect(url_for('dashboard'))
else:
flash('登录失败,请检查邮箱和密码!', 'danger')
return render_template('login.html', form=form)
7.6.3 处理用户登出
python
from flask_login import logout_user
@app.route('/logout')
def logout():
logout_user()
flash('你已退出登录', 'info')
return redirect(url_for('login'))
7.7 访问控制
Flask-Login 提供 @login_required 装饰器,限制未登录用户访问特定页面。
python
from flask_login import login_required
@app.route('/dashboard')
@login_required
def dashboard():
return "欢迎来到用户面板!"
7.8 角色权限管理(RBAC)
7.8.1 修改 User模型,添加** role字段**
python
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
role = db.Column(db.String(10), nullable=False, default='user') # 角色字段
7.8.2 创建权限管理装饰器
python
from functools import wraps
from flask import abort
from flask_login import current_user
def role_required(role):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if current_user.role != role:
abort(403) # 权限不足
return f(*args, **kwargs)
return decorated_function
return decorator
7.8.3 应用到管理员页面
python
@app.route('/admin')
@login_required
@role_required('admin')
def admin_panel():
return "管理员面板"
7.9 API 认证(JWT)
使用 Flask-JWT-Extended 进行 API 认证。
7.9.1 安装 Flask-JWT-Extended
pip install flask-jwt-extended
7.9.2 配置 JWT
python
from flask_jwt_extended import JWTManager
app.config['JWT_SECRET_KEY'] = 'supersecretkey'
jwt = JWTManager(app)
7.9.3 生成 JWT 令牌
python
from flask_jwt_extended import create_access_token
@app.route('/token', methods=['POST'])
def login_jwt():
user = User.query.filter_by(email=request.json.get("email")).first()
if user and bcrypt.check_password_hash(user.password, request.json.get("password")):
access_token = create_access_token(identity=user.id)
return jsonify(access_token=access_token)
return jsonify(msg="用户名或密码错误"), 401
7.10 结语
本章介绍了 Flask 用户认证的完整流程:
- 用户注册
- 登录/登出
- 访问控制
- 基于角色的权限管理
- API 认证
下一章将介绍 Flask 的异步任务与后台处理。