tonyseek / Simple Rbac
Licence: mit
A simple role based access control utility for Python.
Stars: ✭ 250
Programming Languages
python
139335 projects - #7 most used programming language
|Build Status| |Coverage Status| |PyPI Version| |Wheel Status|
Simple RBAC
This is a simple role based access control utility in Python.
Quick Start
- Install Simple RBAC
::
pip install simple-rbac
2. Create a Access Control List
::
import rbac.acl
acl = rbac.acl.Registry()
- Register Roles and Resources
::
acl.add_role("member")
acl.add_role("student", ["member"])
acl.add_role("teacher", ["member"])
acl.add_role("junior-student", ["student"])
acl.add_resource("course")
acl.add_resource("senior-course", ["course"])
4. Add Rules
~~~~~~~~~~~~
::
acl.allow("member", "view", "course")
acl.allow("student", "learn", "course")
acl.allow("teacher", "teach", "course")
acl.deny("junior-student", "learn", "senior-course")
5. Use It to Check Permission
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
if acl.is_allowed("student", "view", "course"):
print("Students chould view courses.")
else:
print("Students chould not view courses.")
if acl.is_allowed("junior-student", "learn", "senior-course"):
print("Junior students chould learn senior courses.")
else:
print("Junior students chould not learn senior courses.")
Custom Role and Resource Class
------------------------------
It’s not necessary to use string as role object and resource object like
"Quick Start". You could define role class and resource class of
yourself, such as a database mapped model in SQLAlchemy.
Whatever which role class and resource class you will use, it must
implement ``__hash__`` method and ``__eq__`` method to be `hashable`_.
Example
~~~~~~~
::
class Role(db.Model):
"""The role."""
id = db.Column(db.Integer, primary_key=True)
screen_name = db.Column(db.Unicode, nullable=False, unique=True)
def __hash__(self):
return hash("ROLE::%d" % self.id)
def __eq__(self, other):
return self.id == other.id
class Resource(db.Model):
"""The resource."""
id = db.Column(db.Integer, primary_key=True)
screen_name = db.Column(db.Unicode, nullable=False, unique=True)
def __hash__(self):
return hash("RESOURCE::%d" % self.id)
def __eq__(self, other):
return self.id == other.id
Of course, You could use the built-in hashable types too, such as tuple,
namedtuple, frozenset and more.
Use the Identity Context Check Your Permission
----------------------------------------------
Obviously, the work of checking permission is a cross-cutting concern.
The module named ``rbac.context``, our ``IdentityContext``, provide some
ways to make our work neater.
1. Create the Context Manager
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
acl = Registry()
context = IdentityContext(acl)
2. Set a Loader
~~~~~~~~~~~~~~~
The loader should load the roles of current user.
::
from myapp import get_current_user
@context.set_roles_loader
def second_load_roles():
user = get_current_user()
yield "everyone"
for role in user.roles:
yield str(role)
3. Protect Your Action
~~~~~~~~~~~~~~~~~~~~~~
Now you could protect your action from unauthorized access. As you
please, you could choose many ways to check the permission, including
python ``decorator``, python ``with statement`` or simple method
calling.
Decorator
^^^^^^^^^
::
@context.check_permission("view", "article", message="can't view")
def article_page():
return "your-article"
With Statement
^^^^^^^^^^^^^^
::
def article_page():
with context.check_permission("view", "article", message="can't view"):
return "your-article"
Simple Method Calling
^^^^^^^^^^^^^^^^^^^^^
::
def article_page():
context.check_permission("view", "article", message="can't view").check()
return "your-article"
Exception Handler and Non-Zero Checking
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Whatever which way you choosen, a exception
``rbac.context.PermissionDenied`` will be raised while a unauthorized
access happening. The keyword arguments sent to the
``context.check_permission`` will be set into a attirbute named
``kwargs`` of the exception. You could get those data in your exception
handler.
::
@context.check_permission("view", "article", message="can not view")
def article_page():
return "your-article"
try:
print article_page()
except PermissionDenied as exception:
print "The access has been denied, you %s" % exception.kwargs['message']
If you don’t want to raise the exception but only check the access is
allowed or not, you could use the checking like a boolean value.
::
if not context.check_permission("view", "article"):
print "Oh! the access has been denied."
is_allowed = bool(context.check_permission("view", "article"))
.. _hashable: http://docs.python.org/glossary.html#term-hashable
.. |Build Status| image:: https://img.shields.io/travis/tonyseek/simple-rbac.svg?style=flat
:target: https://travis-ci.org/tonyseek/simple-rbac
:alt: Build Status
.. |Coverage Status| image:: https://img.shields.io/coveralls/tonyseek/simple-rbac.svg?style=flat
:target: https://coveralls.io/r/tonyseek/simple-rbac
:alt: Coverage Status
.. |Wheel Status| image:: https://img.shields.io/pypi/wheel/simple-rbac.svg?style=flat
:target: https://warehouse.python.org/project/simple-rbac
:alt: Wheel Status
.. |PyPI Version| image:: https://img.shields.io/pypi/v/simple-rbac.svg?style=flat
:target: https://pypi.python.org/pypi/simple-rbac
:alt: PyPI Version
Note that the project description data, including the texts, logos, images, and/or trademarks,
for each open source project belongs to its rightful owner.
If you wish to add or remove any projects, please contact us at [email protected].