Flask-Principal权限控制

本文介绍 Flask-Principal 扩展的使用方法,包括管理员权限限制、用户登录退出时的身份转换、权限加载器的定义及资源保护的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 官方地址:https://pythonhosted.org/Flask-Principal/
  • 学习的步骤: 先学会如何使用,再学会深层原理,而不是上来直接分析原理,因为你分析不明白。
  • 该框架干啥的:权限控制
  • 安装:pip install flask-principal

一: Flask-Principal的使用

1.1: 管理员用户才能访问:

  • 定义一个权限,然后在需要进行权限控制的地方使用装饰器进行装饰就可以了。

  • 如果是一个视图中的部分代码逻辑,需要权限才能执行,那么使用上下文进行管理。

    from  flask  import  Flask ,  Response 
    from  flask.ext.principal  import  Principal ,  Permission ,  RoleNeed
    
    app  =  Flask ( __name__ )
    
    # 加载扩展
    principals  =  Principal ( app )
    
    # 创建具有单个需求的权限,在本例中为 RoleNeed。
    admin_permission  =  Permission ( RoleNeed ( 'admin' ))
    
    # 使用需要的主体保护视图
    @app.route ( '/admin' ) 
    @admin_permission.require () 
    def  do_admin_index (): 
        return  Response ( 'Only if you are an admin' )
    
    # 这次用上下文管理器保护
    @app.route ( '/articles' ) 
    def  do_articles (): 
        with  admin_permission.require (): 
            return  Response ( 'Only if you are admin' )
    

1.2: 登录退出时身份转换:

  • 当用户登录的时候和退出登录的时候,用户是需要进行身份转换的。那么如何处理呢?

  • 用户登录的时候,使用send函数发送消息给当前项目,表示身份发生了转变。

    @app.route('/login', methods=['GET', 'POST'])
    def login():
        # A hypothetical login form that uses Flask-WTF
        form = LoginForm()
    
        # Validate form input
        if form.validate_on_submit():
            # Retrieve the user from the hypothetical datastore
            user = datastore.find_user(email=form.email.data)
    
            # Compare passwords (use password hashing production)
            if form.password.data == user.password:
                # Keep the user info in the session using Flask-Login
                login_user(user)
    
                # 身份发生改变,向程序发送
                identity_changed.send(current_app._get_current_object(),
                                      identity=Identity(user.id))
    
                return redirect(request.args.get('next') or '/')
    
        return render_template('login.html', form=form)
    
  • 当用户退出登录的时候,将身份转变成匿名用户:

    @app.route('/logout')
    @login_required
    def logout():
        # Remove the user information from the session
        logout_user()
    
        # Remove session keys set by Flask-Principal
        for key in ('identity.name', 'identity.auth_type'):
            session.pop(key, None)
    
        # 身份进行转变,变成匿名用户。
        identity_changed.send(current_app._get_current_object(),
                              identity=AnonymousIdentity())
    
        return redirect(request.args.get('next') or '/')
    

1.3: 权限加载器:

  • 整个项目中必须有一个给当前的用户增加权限的函数,而这个函数我们成为权限加载器。

  • 函数名一般来说固定: on_identity_loaded,这个函数必须使用@identity_loaded.connect_via(app)装饰器装饰。

    from flask.ext.login import current_user
    from flask.ext.principal import identity_loaded, RoleNeed, UserNeed
    
    @identity_loaded.connect_via(app)
    def on_identity_loaded(sender, identity):
        # 1:首先拿到当前的用户对象
        identity.user = current_user
    
        # 2:增加当前用户拥有的权限
        if hasattr(current_user, 'id'):
            identity.provides.add(UserNeed(current_user.id))
    
        # 3:如果user中存在一个字段roles表示该用户还拥有的角色(一对多),那么我们可以循环遍历这个角色,将角色加入到身份中去,这样用户就拥有了多种权限。
        if hasattr(current_user, 'roles'):
            for role in current_user.roles:
                identity.provides.add(RoleNeed(role.name))
    

1.4: 资源保护:

  • 需求: 假如时一个博客系统,现在要求,只有作者才能编辑博客。

  • 如何实现?

    • 1: 首先,从表的存储上来讲,user表必须对应着一个posts表(posts权限表), 并且是一对多的关系。(一个user有多个post权限)
    • 2: 当用户登录的时候,我们根据user,拿到所有的post,将这些post加入到当前用户的权限中。(用户有了这些权限)
    • 3: 在进行编辑的时候,前端发送需要传递一个post_id,根据这个post_id构造一个权限。调用permission.can()执行看看这个权限当前用户是否存在,如果存在则进行视图中的逻辑处理。
  • 具体实现:

    • 1: 构造生成权限的类:

      from collections import namedtuple
      from functools import partial
      
      from flask.ext.login import current_user
      from flask.ext.principal import identity_loaded, Permission, RoleNeed, \
           UserNeed
      
      BlogPostNeed = namedtuple('blog_post', ['method', 'value'])
      EditBlogPostNeed = partial(BlogPostNeed, 'edit')
      
      class EditBlogPostPermission(Permission):
          def __init__(self, post_id):
              need = EditBlogPostNeed(unicode(post_id))
              super(EditBlogPostPermission, self).__init__(need)
      
    • 2: 登录的时候,给当前用户赋予权限:

      @identity_loaded.connect_via(app)
      def on_identity_loaded(sender, identity):
      	...
          # Assuming the User model has a list of posts the user
          # has authored, add the needs to the identity
          if hasattr(current_user, 'posts'):
              for post in current_user.posts:
                  identity.provides.add(EditBlogPostNeed(unicode(post.id)))
      
    • 3: 视图逻辑校验的时候,看前端视图需要的权限,该用户是否存在,存在,执行逻辑处理,不存在则抛出403权限异常。

      @app.route('/posts/<post_id>', methods=['PUT', 'PATCH'])
      def edit_post(post_id):
          permission = EditBlogPostPermission(post_id)
      
          if permission.can():
              return render_template('edit_post.html')
      
          abort(403)  # HTTP Forbidden
      

二: 原理分析:

2.1: flask_principal四大主件:

  • 1: Identity(身份): 一个用户对应一个身份,一个身份有众多的权限。
  • 2: Permission(权限): 满足某种需求的能力。
  • 3: Needs(访问控制单元) : 分为两类: 角色需求(管理员,超级管理员),动作需求(可以编辑,可以上传图片)
  • 4: IdentityContext(权限上下文) : 有关权限的装饰器(权限处理)和上下文管理器(权限控制)。
"""
白话讲解: 
1:身份是个啥? 来一个人,我就给你发个牌子,代表你的身份。
2:权限是个啥? 一个是表示你职位(职位能做的都能做),一个代表你还能干啥(例如:领导单独给你的权力)。
3:访问控制单元是个啥?职位对应能做的事,单独权力能做的事。
4:权限上下文是个啥?你这个身份咋就有了权限(装饰器控制),咋判断有没有权限(装饰器或者上下文管理器),这些权限上下文处理了,作为码农的我们就不要考虑了。
"""
  • 官方图解:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奈何桥上的幽灵野草

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值