• 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)
        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))
    

      

  • 相关阅读:
    POJ 2794 Exploring Pyramids
    POJ 2282 The Counting Problem
    eclipse中设置java注释模板
    eclipse复制工程需要注意的地方
    extjs的强大利器GUI设计工具(extjs designer)
    eclipse项目名前出现红色感叹号,小红叉解决(转)
    上传一份个人学习struts2的历程笔记
    struts2中的action与actioncontext的理解
    J2EE后台UI系统框架搭建EXTJs使用(4.1 GPL版本)
    java.lang.OutOfMemoryError: Java heap space 解决方法转测试可用
  • 原文地址:https://www.cnblogs.com/liushaocong/p/7426811.html
Copyright © 2020-2023  润新知