此前我们创建了登录、注册模块,那么自然也需要有身份的转变,如从游客→用户
这里我们使用Flask-Principal来实现用户的权限设置
首先,安装Flask-Principal
那相应地,我们需要一个身份表来表示身份
先添加关联表(models.py)
roles = Table('role_users', db.Model.metadata,
Column('u_id', Integer(), ForeignKey('user.id')),
Column('r_id', Integer(), ForeignKey('role.id')))
给User表添加关联(models.py)
class User(db.Model):
...
roles = relationship('Role', secondary=roles, backref=backref('users', lazy='dynamic'))
添加Role表(models.py)
class Role(db.Model):
id = Column(Integer(), primary_key=True)
name = Column(String(80), unique=True)
description = Column(String(255))
def __init__(self, name):
self.name = name
def __repr__(self):
return "<Role '{}'>".format(self.name)
接着,我们在shell中为role表添加3个角色(管理员,文章作者,默认用户)
开始对Principal进行初始化:
Flask Principal提供了两种Need对象:UserNeed和RoleNeed
每种身份会关联到Need对象(定义了该身份能做什么事情)
打开extensions.py:
from flask_principal import Principal, Permission, RoleNeed
principals = Principal()
admin_permission = Permission(RoleNeed('admin'))
poster_permission = Permission(RoleNeed('poster'))
default_permission = Permission(RoleNeed('default'))
...
在app中注册:
from webapp.extensions import bcrypt, login_manager, principals
from flask_principal import identity_loaded, UserNeed, RoleNeed
from flask_login import current_user
def create_app(object_name):
...
principals.init_app(app)
@identity_loaded.connect_via(app)
def on_identity_loaded(sender, identity):
identity.user = current_user
if hasattr(current_user, 'id'):
identity.provides.add(UserNeed(current_user.id))
if hasattr(current_user, 'roles'):
for role in current_user.roles:
identity.provides.add(RoleNeed(role.name))
其中,我们结合了flask_login的current_user来获取当前用户状态(身份)
在create_app()函数中定义了on_identity_loaded()函数:来获取用户的权限(角色)
然后我们需要进行身份的转变,如:游客→文章作者,游客→管理员:
我们打开main,py修改视图函数:
from flask_principal import Identity, AnonymousIdentity, identity_changed
from flask import current_app
...
@main_blueprint.route('/login', methods=['GET', 'POST'])
def login():
if form.validate_on_submit():
...
if form.validate():
login_user(user, remember=form.remember.data)
identity_changed.send(current_app._get_current_object(), identity=Identity(user.id))
return redirect(request.args.get('next') or url_for('main.index'))
@main_blueprint.route('/logout', methods=['GET', 'POST'])
def logout():
from flask_login import logout_user
logout_user()
identity_changed.send(current_app._get_current_object(), identity=AnonymousIdentity())
...
那么我们现在就可以使用角色权限了,比如只有文章作者才可以进入文章编辑页面:
我们打开blog.py:
from flask_login import login_required
from webapp.extensions import poster_permission
@blog_blueprint.route('/edit/<int:id>', methods=['GET', 'POST'])
@login_required
@poster_permission.require(http_exception=403)
def edit_post(id):
...
因为我们希望管理员也有权限进行修改,所以可以改成
from webapp.extensions import poster_permission, admin_permission
from flask_principal import Permission, UserNeed
from flask import abort
@blog_blueprint.route('/edit/<int:id>', methods=['GET', 'POST'])
@login_required
@poster_permission.require(http_exception=403)
def edit_post(id):
post = Post.query.get_or_404(id)
permission = Permission(UserNeed(post.user.id))
if permission.can() or admin_permission.can():
form = PostForm()
if form.validate_on_submit():
post.title = form.title.data
post.text = form.text.data
post.publish_date = datetime.datetime.now()
db.session.add(post)
db.session.commit()
return redirect(url_for('blog.post', post_id=post.id))
form.text.data = post.text
return render_template('edit.html', form=form, post=post)
abort(403)