一、Flask-Admin 框架
Flask-Admin 贯彻了'极简'理念,能用最少代码快速获得功能齐全的后台管理系统。
安装依赖:
pip install flask-admin
在 Flask 应用中增加配置和挂载到 Flask 上:
from flask_admin import Admin
app.config['SECRET_KEY'] = '12345678'
admin = Admin(app, name='测试后台')
将 SQLAlchemy 模型挂载到管理后台的视图上:
from flask_admin.contrib.sqla import ModelView
admin.add_view(ModelView(Test, db.session))
完整代码示例:
from flask import Flask, jsonify, request
from model import db, SQLALCHEMY_DATABASE_URI, Test
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI
app.config['SECRET_KEY'] = '12345678'
admin = Admin(app, name='测试后台')
admin.add_view(ModelView(Test, db.session))
db.init_app(app)
@app.route('/tests', methods=['GET'])
def get_tests():
tests = Test.query.all()
data = [test.to_dict() for test in tests]
return jsonify(data)
@app.route('/')
def index():
return 'Hello, World!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=True)
二、初步结果展示
启动程序,访问管理页面:
python Flask.py http://127.0.0.1:8080/admin/
Test 表实现了轻松的增删改查。
三、用于登录的数据表
1. 新增角色管理专用 user 表
在 model.py 新增用户表,用作角色管理:
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(255), unique=True, nullable=False)
password = db.Column(db.String(255), nullable=False)
is_active = db.Column(db.Boolean, default=True)
def set_password(self, password):
from werkzeug.security import generate_password_hash
self.password = generate_password_hash(password)
def check_password(self, password):
from werkzeug.security import check_password_hash
return check_password_hash(self.password, password)
密码不可以存明码(理论上也要随机加盐)。
2. 将用户管理表也添加到后台管理中(测试与演示)
一次性自动生成一个哈希密码:
admin.add_view(ModelView(User, db.session, category='系统管理'))
首次运行自动创建默认管理员(仅开发/首次部署用):
with app.app_context():
db.create_all()
if not User.query.filter_by(username='admin').first():
admin_user = User(username='admin')
admin_user.set_password('123456')
db.session.add(admin_user)
db.session.commit()
此时打开后台将可以看到,user 表的密码是自动哈希后的结果。但是此时依旧没有拦截,可以随意访问 admin。
四、Flask-Login 框架
1. Flask-Login 到底解决什么问题(核心逻辑)
- 负责登录状态管理:登录/退出
- 记住当前登录用户
- 登录保护,限制访问有权限的页面
- 它只负责:'这个请求是不是某个用户发的'
2. 如何从普通的数据表到登录管理
User 模型表,密码哈希(不能存明码),让 User 表继承 flask_login.UserMixin:
class User(db.Model, UserMixin):
""" Flask-Login 识别用户的核心模型 """
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(255), unique=True, nullable=False)
password = db.Column(db.String(255), nullable=False)
is_active = db.Column(db.Boolean, default=True)
def set_password(self, password):
from werkzeug.security import generate_password_hash
self.password = generate_password_hash(password)
def check_password(self, password):
from werkzeug.security import check_password_hash
return check_password_hash(self.password, password)
继承 UserMixin,该类自动提供了四个函数:is_authenticated, is_active, is_anonymous, get_id()。Flask-Login 就靠 get_id() 把用户 ID 存进 session。
3. 在主程序中增加登陆管理
初始化 LoginManager:
from flask_login import LoginManager
login_manager = LoginManager()
login_manager.login_view = 'login' # 未登录跳转地址
4. 注册登陆管理到主 Flask 程序中
db.init_app(app)
login_manager.init_app(app)
测试,到现在为止还是没有拦截,因为还没有给 admin 加门禁,只是在配置 login。
5. 配置服务端 session 根据 id 查管理员用户
单独写一个带装饰器的函数:
@login_manager.user_loader
def load_user(user_id):
""" Flask-Login 会自动调用这个函数 用 session 里的 user_id 反查 User 对象 """
return User.query.get(int(user_id))
原理如下: 请求进来 -> session 里是否有 user_id -> 有 -> load_user(user_id) -> current_user = User 对象。
6. 创建登录页面且在成功时调用函数存 ID 入 session
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
user = User.query.filter_by(username=username).first()
if user and user.check_password(password):
login_user(user) # 核心
return redirect('/admin')
return '用户名或密码错误', 401
return '''
<form method="post">
用户名:<input name="username"><br>
密码:<input name="password" type="password"><br>
<input type="submit" value="登录">
</form>
'''
login_user 是 flask-login 库自带的将用户 id 获取并且存入 session 的函数。
额外:可以在控制页面上加一个登出按钮,利用两个库函数即可:
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect('/login')
现在访问 ip:/admin 依旧是不受控制的,因为 Login 不知道该保护哪些页面。
7. 给 Flask-Admin 加门禁,将部分页面保护起来
原来的后台管理页面调用了 ModelView,而 ModelView 可以被继承并且重写其内部函数:首先它有一个 is_accessible 函数,默认是 true,还有一个 inaccessible_callback,当前一个函数返回 false 时会调用这个回调函数。那就自定义一个安全 modelview:
from flask_login import current_user
from flask_admin.contrib.sqla import ModelView
class SecureModelView(ModelView):
def is_accessible(self):
# 自定义的总会调用 session 里当前用户是否认证函数
return current_user.is_authenticated
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for('login'))
8. 替换新的 ModelView,完成保护流程
admin = Admin(app, name='测试后台')
admin.add_view(SecureModelView(Test, db.session, category='测试'))
admin.add_view(SecureModelView(User, db.session, category='用户管理'))
此时刷新页面发现,必须输入账号密码才能进入管理平台。
总结
注意事项:
- 不要暴露简单 admin 给前台,而是独立主页开设登录接口,可以使用随机函数动态刷新路径。
- 密码配置最好存到环境变量里,避免硬编码。
- 使用 HTTPS 访问。
- 登录错误次数检测,可在 user 表中增加登录次数和锁定时间字段。
- 核心原则:隐藏入口、强化认证、加密传输、主动防御。
| 功能类别 | 功能模块 |
|---|---|
| 权限与安全 | 身份管理、角色权限控制(RBAC)、操作日志、安全防护 |
| 数据与内容 | 数据管理(CRUD)、内容管理(CMS)、统计报表与可视化 |
| 流程与集成 | 工作流引擎、第三方系统集成(API) |
| 运维与配置 | 系统参数配置、消息/通知中心 |


