app/models.py

class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
default = db.Column(db.Boolean, default=False, index=True)
permissions = db.Column(db.Integer)
users = db.relationship('User', backref='role', lazy='dynamic')

程序的权限

FOLLOW         关注用户              0x01

COMMET         在他人文章中发表评论  0x02

WRITE_ARTICLES     写文章         0x04

MODERATE_COMMENTS    管理他人发表的评论   0x08

ADMINISTER        管理员权限       0x80

class Permission:
FOLLOW = 0x01
COMMENT = 0x02
WRITE_ARTICLES = 0x04
MODERATE_COMMENTS = 0x08
ADMINISTER = 0x80

列出了要支持的用户角色以及定义角色使用的权限位

用户角色

匿名        0x00      未登录的用户,在程序中只有阅读权限

用户        0x07      具有发表文章,发表评论和关注其他用户的权限。这是新用户的默认角色

协管员       0x0f       增加审查不当评论的权限

管理员       0xff       具有所有权限,包括修改其他用户所属角色的权限

app/models.py:在数据库中创建角色

class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
default = db.Column(db.Boolean, default=False, index=True)
permissions = db.Column(db.Integer)
users = db.relationship('User', backref='role', lazy='dynamic') @staticmethod
def insert_roles():
roles = {
'User': (Permission.FOLLOW |
Permission.COMMENT |
Permission.WRITE_ARTICLES, True),
'Moderator': (Permission.FOLLOW |
Permission.COMMENT |
Permission.WRITE_ARTICLES |
Permission.MODERATE_COMMENTS, False),
'Administrator': (0xff, False)
}
for r in roles:
role = Role.query.filter_by(name=r).first()
if role is None:
role = Role(name=r)
role.permissions = roles[r][0]
role.default = roles[r][1]
db.session.add(role)
db.session.commit()

这个Role表添加了一个静态方法,执行insert_roles函数会创建三个name,分别是用户,协管员和管理员

赋予角色:

app/models.py

class User(UserMixin,db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64),unique=True,index=True)
username = db.Column(db.String(64), unique=True,index=True)
role_id = db.Column(db.Integer,db.ForeignKey('roles.id'))
password_hash = db.Column(db.String(128)) def __init__(self,**kwargs):
super(User,self).__init__(**kwargs)
if self.role is None:
if self.email == current_app.config['FLASKY_ADMIN']:
self.role = Role.query.filter_by(permission=0xff).first()
if self.role is None:
self.role = Role.query.filter_by(default=True).first()

User表的方法是:如果用户没有设置权限,用户的邮箱等于配置中设置的管理员邮箱,就设置为管理员权限,用户的权限为空,则设置为普通用户

角色验证

app/models.py:检查用户是否有指定的权限

class User(UserMixin,db.Model):

    #...

    def can(self, permissions):
return self.role is not None and \
(self.role.permissions & permissions) == permissions def is_administrator(self):
return self.can(Permission.ADMINISTER)

can()方法在请求和赋予角色这两种权限之间进行位与操作。如果角色中包含请求的所有权限位,则返回True ,表示允许用户执行此项操作。

is_administrator()方法用来检车管理员权限

from flask_login import AnonymousUserMixin
class AnonymousUser(AnonymousUserMixin):
def can(self,permissions):
return False def is_administraror(self):
return False login_manager.anonymous_user = AnonymousUser

 这个类用来检查匿名用户的权限

app/decorators.py:检查用户权限的自定义修饰器

from functools import wraps
from flask import abort
from flask_login import current_user
from .models import Permission def permission_required(permission):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not current_user.can(permission):
abort(403)
return f(*args, **kwargs)
return decorated_function
return decorator def admin_required(f):
return permission_required(Permission.ADMINISTER)(f)

这两个修饰器都使用了Python标准库中的functools包,如果用户不具有指定权限,则返回403错误码,即HTTP“禁止”错误。要添加一个403错误页面

以下的例子就是将上面的装饰器,用在了路由功能里面,针对一些页面设置了权限

from decorators import admin_required, permission_required
from .models import Permission
@main.route('/admin')
@login_required
@admin_required
def for_admins_only():
return "For administrators!" @main.route('/moderator')
@login_required
@permission_required(Permission.MODERATE_COMMENTS)
def for_moderators_only():
return "For comment moderators!"

  

在模板中可能也需要检查权限,所以Permission 类为所有位定义了常量以便于获取。为了避免每次调用render_template() 时都多添加一个模板参数,可以使用上下文处理器。上下文处理器能让变量在所有模板中全局可访问。

app/main/__init__.py:把Permission类加入模板上下文

@main.app_context_processor
def inject_permissions():
return dict(Permission=Permission)

 

tests/test_user_models.py:角色和权限的单元测试

#...

    def test_roles_and_permissions(self):
Role.insert_roles()
u = User(email='1808863623@qq.com',password='cat')
self.assertTrue(u.can(Permission.WRITE_ARTICLES))
self.assertFalse(u.can(Permission.MODERATE_COMMENTS)) def test_anonymous_user(self):
u = AnonymousUser()
self.assertFalse(u.can(Permission.FOLLOW))

  

最新文章

  1. SQLServer 创建dtsx包更新统计信息(示例)
  2. C#遍历Dictionary
  3. 【Java每日一题】20161109
  4. 基于jquery的-获取短信验证码-倒计时
  5. c# 小数取整
  6. hdu 1031 (partial sort problem, nth_element, stable_partition, lambda expression) 分类: hdoj 2015-06-15 17:47 26人阅读 评论(0) 收藏
  7. 【Reporting Services 报表开发】— 级联式参数设置
  8. Drupal 7.23:函数module_invoke_all()注释
  9. Cracking the coding interview 第二章问题及解答
  10. 【C语言学习】存储类型
  11. Java 脚本引擎
  12. 编写第一个spring MVC程序
  13. Coding使用方法
  14. Relax信息学题库须知
  15. 了解Scala反射
  16. 面试官:说说一条查询sql的执行流程和底层原理?
  17. Python爬虫:爬取人人都是产品经理的数据
  18. faces
  19. P2331 [SCOI2005]最大子矩阵
  20. Django 浏览器打开警告Not Found: /favicon.ico (转)

热门文章

  1. php设计模式-单例
  2. 1143 纪念品分组 2007年NOIP全国联赛普及组
  3. td 内容自动换行 table表格td设置宽度后文字太多自动换行
  4. Linux命令-4类
  5. UVA 110020 Efficient Solutions (STL)
  6. Robot Framework(一)入门
  7. k8s1.13.0二进制部署-master节点(三)
  8. openstack keystone修改horizon密码
  9. 用requests爬取图片
  10. jvm | 基于栈的解释器执行过程