zoukankan      html  css  js  c++  java
  • Flask 学习 八 用户角色

     角色在数据库中表示

    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)# 位标志,各个操作都对应一个位位置,能执行某项操作的角色,其位会被设为1
        users = db.relationship('User',backref='role',lazy='dynamic')# 不加载记录,但是提供加载记录的查询

    程序的权限 里面的位值。

    权限常量app/models.py

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

    用户角色

    使用权限组织角色(不同角色拥有的权限利用位运算进行组合)

    在Role类中写一个insert_roles方法来完成将角色添加到数据库中的操作

    @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() # 提交数据库

    赋予角色

    app/models.py

    管理员的管理员角色保存在设置变量FLASK_ADMIN中的电子邮件地址识别,只要这个电子邮件出现注册请求,就会被正确赋予角色

    class User(UserMixin,db.Model):
        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(permissions=0xff).first() # 设置其为管理员
                if self.role is None: # 或者设置为默认角色
                    self.role=Role.query.filter_by(default=True).first()

    角色认证

    为了简化角色和权限的实现过程,在User中添加一个辅助方法,检查是否有正确权限

    from flask_login import UserMixin,AnonymousUserMixin # 匿名用户角色
    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)
    class AnonymousUser(AnonymousUserMixin):
        def can(self, permissions):
            return False
        def is_administrator(self):
            return False
    # 用户未登录时current_user的值,并且不用用户登陆即可检查用户权限
    login_manager.anonymous_user=AnonymousUser

    让视图函数只对具有特定权限的用户开放,可以自定义装饰器,一个检查常规权限,一个检查管理员权限

    app/decorators.py

    from flask import abort
    from flask_login import current_user
    from app.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) # 如果不具备该权限,返回403错误码
                return f(*args,**kwargs)
            return decorated_function
        return decorator
    
    def admin_required(f):
        return permission_required(Permission.ADMINISTER)(f)
    # 举例演示使用权限检查装饰器
    from app.decorators import admin_required,permission_required
    from ..models import Permission
    from flask_login import login_required
    
    @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_moderator_only():
        return 'For comment moderator'

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

    app/main/__init__.py

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

    新添加角色和权限在单元测试中测试

    test/test_user_model.py

    class UserModelTestCase(unittest.TestCase):
        def test_roles_and_permissions(self):
            Role.insert_roles()
            u = User(email='join12@example.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))
  • 相关阅读:
    typeOf操作符及数据类型
    图片轮播 js
    百度地图API学习
    jq 使页脚固定在底部
    js 动态自动添加 删除
    background-size 兼容ie8以下浏览器的方法
    opacity css3 ie8以下兼容方法
    ie 6、7/position: absolute bug解决方法
    IE 下的rgba背景透明
    2017腾讯实习生春招前端初面总结
  • 原文地址:https://www.cnblogs.com/Erick-L/p/6892313.html
Copyright © 2011-2022 走看看