跳转到主要内容

基于Flask-User构建的KegElements的三层权限模型

项目描述

https://circleci.com/gh/level12/keg-bouncer.svg?style=svg https://codecov.io/github/level12/keg-bouncer/coverage.svg?branch=master

一个关于Keg应用中认证和授权相关事宜的一站式商店。

简介

基于KegKegElements构建的啤酒弹跳器提供了一系列管理授权和认证的功能。啤酒弹跳器允许您选择在您的应用程序中处理哪些功能。它通过提供每个功能的Mixin类来实现,您可以选择性地将这些类混入您的实体(可能是User实体)。

可用的混入包括

  • 三层权限系统

  • 基于密码的认证和密码历史记录

  • 登录历史记录

有关如何使用这些功能的详细信息,请参阅以下部分。

主键要求

请注意,每个mixin将自动确定您的实体主键。但是,您的实体必须恰好有一个主键,并且必须将其指定为SQLAlchemy声明性类的属性。

权限

为了使用KegBouncer的授权功能来保护Keg视图,您还需要Flask-Login。然而,KegBouncer的模型不需要这个依赖。

keg_bouncer.mixins.PermissionMixin提供了一种三级权限模型。它管理四种类型的实体

  • 用户

  • 权限(用于描述系统内可以受保护的行动)

  • 用户组(按最能满足业务需求的方式分组用户)

  • 权限包(按最能满足系统的方式分组权限)

我们称之为“三级”权限模型,因为用户可以通过三种方式获得权限

  1. 直接

  2. 通过权限包

  3. 通过用户组

这个术语是为了将此权限模型与其他模型区分开来,如允许任何深度的层次结构的RBAC。技术上,这个三级模型是RBAC的特殊情况。

关于术语“角色”的说明:虽然这个模型在技术上是一种广泛使用的基于角色的访问控制(RBAC)的特殊情况,但我们尽量避免使用高度模糊的术语“角色”。

用法

要将权限功能添加到您的用户实体中,像这样继承PermissionMixin

import flask_login  # Only necessary if using KegBouncer to protect you views.
from sqlalchemy import import Column, Integer, String

Base = sqlalchemy.ext.declarative.declarative_base()

class User(Base, flask_login.UserMixin, keg_bouncer.model.mixins.PermissionMixin):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)

保护视图和组件

为了保护您应用程序的各个部分,您可以使用keg_bouncer.auth提供的工具

为了利用这些工具,您的User实体也需要混入flask_login.UserMixin

  1. 使用if块并检查权限

    # ...
    if keg_bouncer.auth.current_user_has_permissions('launch-missiles'):
        launch_missiles()
  2. 装饰一个函数

    # ...
    @keg_bouncer.auth.requires_permissions('launch-missiles')
    def launch_missiles(target=Enemy())
        # ...
  3. ProtectedBaseView继承

    # ...
    class LaunchMissilesView(keg_bouncer.auth.ProtectedBaseView):
        requires_permission = 'launch-missiles'

迁移

KegBouncer使用Alembic来管理迁移,并假定您的应用程序也是如此。

要使用KegBouncer提供的迁移,您需要告诉Alembic在哪里找到修订版。在您的应用程序的alembic.ini文件中,调整您的version_locations设置以包括KegBouncer的版本文件夹。

[alembic]
version_locations = alembic/versions keg_bouncer:alembic/versions

如果您运行alembic heads,您现在应该看到两个heads,一个用于您的应用程序,一个用于KegBouncer。

$ alembic heads
51ba1b47505e (application) (head)
13d265b97e4d (keg_bouncer) (head)

应用程序有多个heads是完全正常的,但您需要独立升级它们。更好的选择是将两个heads合并为一个。使用alembic merge命令来完成此操作。

$ alembic merge -m "pull KegBouncer into application" 51ba1b 13d265
Generating /path/to/app/alembic/versions/31b094b2844f_pull_keg_bouncer_into_application.py ... done

如果您再次运行alembic heads,您会发现只有一个heads。

$ alembic heads
31b094b2844f (application, keg_bouncer) (head)

此外,在这个合并修订版中,您还需要为您的User实体(它混入了keg_bouncer.model.mixins.PermissionMixin)创建一些链接表。

基于密码的认证

要将基于密码的认证添加到您的实体中,您需要动态构建一个密码mixin对象并将其混入到您的实体中。

from keg_bouncer.model import mixins
from passlib.context import CryptContext
import sqlalchemy as sa

crypt_context = CryptContext(schemes=['bcrypt'])

# This mixin is optional but allows you to add additional fields to the password history table.
class OptionalAdditionalFields(object):
    another_field = sa.Column(sa.Integer)


password_history_mixin = mixins.make_password_mixin(
    OptionalAdditionalFields,    # [optional] Allows you to add more fields to the password
                                 # history table via a mixin
    crypt_context=crypt_context  # [optional, but must be provided here or via another means]
                                 # Configures the CryptContext for hashing and verifying
)


class User(password_history_mixin):
    default_crypt_context = crypt_context  # An alternative way of specifying your CryptContext

    # Yet another way to specify your CryptContext
    def get_crypt_context(self):
        return crypt_context


help(User.set_password)  # Adds password to password history

help(User.verify_password)  # Verifies a password against most recent password

help(User.is_password_used_previously)  # Looks for password in history

help(User.password_history_entity)  # SQLAlchemy entity defining password history entries

User.password_history  # SQLAlchemy relationship for past passwords;
                       # sorted in reverse chronological order

注意:如果您使用is_password_used_previously或类似的概念,您选择的散列算法可以极大地影响性能,因为密码验证是有意设计为缓慢的。例如,使用bcrypt而不是sha256_crypt可以使您大约快两倍地验证密码。这在您在旧密码中筛选时会有很大影响。

登录历史记录

要将登录历史记录添加到您的实体中,您需要动态构建一个历史记录mixin对象并将其混入到您的实体中。

from keg_bouncer.model import mixins
import sqlalchemy as sa

# This mixin is optional but allows you to add additional fields to the login history table.
class OptionalAdditionalFields(object):
    another_field = sa.Column(sa.Integer)


login_history_mixin = mixins.make_login_history_mixin(
    OptionalAdditionalFields,  # [optional] Allows you to add more fields to the login history
                               # table via a mixin
)


class User(login_history_mixin):
    pass


help(User.login_history_entity)  # SQLAlchemy entity defining login history entries

User.login_history  # SQLAlchemy relationship for past logins;
                    # sorted in reverse chronological order

# Example use:
def register_login(user):
    user.login_history.insert(0, user.login_history_entity(is_login_successful=True))

开发

分支和状态

  • master:我们的“生产”分支

所有其他分支都是功能分支。

项目需求

查看 requirements 目录中的所需文件和注意事项。

  • 您应该克隆 Keg 和 KegElements,然后执行 pip install -e . 以获取工作副本。由于这些库是新的,它们可能会频繁更改。

  • 如果遇到问题,请阅读 requirements 文件中的说明。

  • 有一个名为 build-wheelhouse.py 的脚本,可以在添加了新的需求时运行。它始终重新构建 wheel-only.txt 中的库,因此 Git 将始终显示它们已更改。但如果它们实际上没有更改,您应该撤销这些文件,以免将“静态”添加到提交中。

开发环境

为了快速设置开发时的虚拟环境,您可以使用提供的脚本之一。

如果您使用 pyenv + virtualenv,请使用 source scripts/make-env-venv.sh

如果您使用 vex,请使用 source scripts/make-env-vex.sh

代码检查

通过安装预提交钩子来防止提交代码检查错误。

ln -s scripts/pre-commit .git/hooks

项目详情


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解有关 安装软件包 的更多信息。

源代码分发

KegBouncer-2.2.4.tar.gz (24.3 kB 查看哈希值)

上传时间 源代码

构建分发

KegBouncer-2.2.4-py2.py3-none-any.whl (17.3 kB 查看哈希值)

上传时间 Python 2 Python 3

由以下支持