通过前两次的努力,我们对环境有了增删查改以及部署和查看日志的能力。 现在已经处于将就可用的状态。但其实还差了很重要的东西,就是权限的管理。 因为不能说每个用户上来都能随便的重启和删除环境吧,太容易出事故了。所以我们想起码有最基本的隔离性。
上一次我们使用了 Flask-WTF 这个针对于表单的扩展模块。 这次为了加入权限管理,我们需要再安装以下这些扩展模块。
涉及到权限就需要有用户的概念,我们需要数据库来存储我们用户和环境的信息,所以要使用 Flask-SQLAlchemy 和 Flask-MySQLdb(我使用的是 mysql)。为了解决用户登录的问题引入 Flask-Login, 为了生成角色和权限的概念引入 Flask-Security。这里解释一下 Flask-Security,它无法单独使用,更像是 Flask-Login 和 Flask-SQLAlchemy 的扩展。 是为了增强他们的权限控制能力而存在的。所以再加入 Flask-Security 后,Flask-SQLAlchemy 和 Flask-Login 的使用方式都跟以前有些不太一样了。接下来我会一个一个介绍
我们先解决数据库的问题吧。 再安装好上面的所有模块后 (注:缺一不可),我们首先要在数据库中创建名叫 env 的库。供我们使用
再启动 app 前设置一下数据库参数:
# 连接mysql数据库的配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/env'
然后我们创建一个 models.py
from __init__ import *
from flask_security import RoleMixin, UserMixin
# Create database connection object
db = SQLAlchemy(app)
# Define models
roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
active = db.Column(db.Boolean())
confirmed_at = db.Column(db.DateTime())
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
envs = db.relationship('Env', backref=db.backref('user'))
class Env(db.Model):
def __init__(self, name, user_id):
self.name = name
self.user_id = user_id
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), unique=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
看到这么一坨代码可能有点懵逼。我来解释解释吧。 Flask-SQLAlchemy 是一个 ORM 框架,它组织了数据库表到类的影射。所以我们可以使用管理这些类对象的方式管理数据库。 你看到上面我们创建了 User,Env 和 Role 类,分别对应了用户,环境和角色。它们都集成了 db.Model。我们把 SQLAlchemy(app) 赋值给 db,这是初始化我们数据库的方式。 然后你会发现 User 和 Role 又分别继承了 UserMixin 和 RoleMixin。暂时可以不用管它, 这个是 Flask-Security 的东西。 表之间的关系我用外键来定义,额,虽然我知道外键的性能不好。开发人员几乎从来不用。但是我这么个小玩意就不在意这些有的没的了,一共就没几条数据。看到上面对 roles_users 的定义可能大家会觉得有点懵逼。 这是 SQLAlchemy 处理多对多关系的方式:产生一张中间表。 SQLAlchemy 处理表关系的方式就是 relationship 方法。这部分内容有点多~~ 具体详细的 API 定义请大家参考官方文档:快速入门 — Flask-SQLAlchemy 2.0 documentation
接下来我们只需要调用下面的代码就会在数据库创建出这些表了。
db.create_all()
3 张表加一个 roles_users 的表。
现在我们有表了,我们想初始化一些数据。 所以我们先看看一些基础的操作。
例如我们想创建一个环境信息,我们可以这么做:
env = Env()
env.name = 'test01'
env.user_id = '1'
db.session.add(env)
db.session.commit()
这是添加一条数据的方式。 只要是增删改的操作,只要没有运行 db.session.commit(), 就不会真正的入库。 这是为了保证事务性。增加了一条数据后,现在我们来查询数据:
env = Env.query.filter_by(name='test01').first()
由于我们 model 的类都继承了 db.Models。 所以我们可以使用一些方法来进行查询。 也可以使用一些复杂一点的查询方式,如下:
Env.query.filter(name.endswith('01')).all()
OK,现在我们看看一开始没有说明的 UserMixin 和 RoleMixin。上面说过他们是 Flask-Security 针对 Flask-SQLAlchemy 做的扩展。通过 Flask-Security 我们可以很方便的管理用户权限但是它对我们的 model 有一定的要求。请看下图:
就是说我们一定要有 User 和 Role 这两张表以及包含相应的字段。 这样 Flask-Security 才能够帮助我们生成权限管理的解决方案。举个简单的例子,通过使用 Flask-Security, 我们可以用下面的方式创建用户:
from urls import db, User, Role
from flask_security import SQLAlchemyUserDatastore, Security
# Setup Flask-Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
db.create_all()
admin = user_datastore.create_user(email='[email protected]', password='admin')
# 生成普通用户角色和admin用户角色
user_datastore.create_role(name='User', description='Generic user role')
admin_role = user_datastore.create_role(name='Admin', description='Admin user role')
# 为admin添加Admin角色
user_datastore.add_role_to_user(admin, admin_role)
db.session.commit()
上面是我初始化数据库的代码。 为了能使用 Flask-Security。我们使用 SQLAlchemyUserDatastore 来封装 db, 使用 Security 封装我们的 web app。 接下来就可以看到我们使用很方便的方式创建 user 和 role。 并且使用 add_role_to_user 的方式为一个用户添加角色。Flask-Security 为我们提供了很多有用的方法。请看下面的截图:
更多的 API 请查看官方文档:API — Flask-Security 3.0.0 documentation
上面说的这些方法都可以很有效的管理我们数据库中 User 和 Role 的关系。再下一篇帖子中,我会详细介绍如何使用 Flask-Security 来做权限控制。今天太晚了~ 先这样吧
另外欢迎大家加入我的知识星球, 最近正在更新手把手教你人工智能测试系列。