Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/bouncer-app/bouncer

Declarative Authentication DSL inspired by Ryan Bates excellent cancan library
https://github.com/bouncer-app/bouncer

Last synced: 3 months ago
JSON representation

Declarative Authentication DSL inspired by Ryan Bates excellent cancan library

Awesome Lists containing this project

README

        

bouncer
=======

Simple Declarative Authentication DSL inspired by Ryan Bates’ excellent
cancan library

.. image:: https://travis-ci.org/jtushman/bouncer.svg?branch=master
:alt: travis-badge
:target: https://travis-ci.org/bouncer-app/bouncer

Introduction
------------

Meet **bouncer**.

**bouncer** is your faithful servant. Big, burly, trustworthy – smarter
than he looks, but very effective in what he does. You just have to talk
simply to him. For example:

.. code:: python

from bouncer import authorization_method
from bouncer.constants import *

@authorization_method
def authorize(user, they):

if user.is_admin:
they.can(MANAGE, ALL)
else:
they.can(READ, ALL)
they.cannot(READ, 'TopSecretDocs')

def if_author(article):
return article.author == user

they.can(EDIT, 'Article', if_author)

And once you have that setup, you can ask questions like:

.. code:: python

jonathan = User(name='jonathan',admin=False)
marc = User(name='marc',admin=False)

article = Article(author=jonathan)

print can(jonathan, EDIT, article) # True
print can(marc, EDIT, article) # False

# Can Marc view articles in general?
print can(marc, VIEW, Article) # True

Installation
------------

``pip install bouncer``

Defining Abilities
------------------

@authorization_method
~~~~~~~~~~~~~~~~~~~~~
User permissions are defined in a method decorated with
``@authorize_method``

A simple setup looks like so …

.. code:: python

@authorization_method
def authorize(user, they):

if user.is_admin:
they.can(MANAGE, ALL)
else:
they.can(READ, ALL)

def if_author(article):
return article.author == user

they.can(EDIT, Article, if_author)

If you do not think the “they.can” is pythonic enough you can use the ``append`` syntax

.. code:: python

@authorization_method
def authorize(user, abilities):

if user.is_admin:
abilities.append(MANAGE, ALL)
else:
abilities.append(READ, ALL)

# See I am using a string here
abilities.append(EDIT, 'Article', author=user)

Alternative syntax
~~~~~~~~~~~~~~~~~~

``dict`` syntax
^^^^^^^^^^^^^^^
You can also use an alternative ``dict`` syntax. The following is equivalent to above:

.. code:: python

@authorization_method
def authorize(user, they):

if user.is_admin:
they.can(MANAGE, ALL)
else:
they.can(READ, ALL)
they.can(EDIT, Article, author=user)

You can add multiple conditions to the ``dict``:

.. code:: python

they.can(READ, Article, published=True, active=True)

Strings instead of classes
^^^^^^^^^^^^^^^^^^^^^^^^^^
You can use strings instead of classes. This means you do not need to import a bunch of files you are not using in initialization

.. code:: python

@authorization_method
def authorize(user, they):

if user.is_admin:
they.can(MANAGE, ALL)
else:
they.can(READ, ALL)

# Notice that I am using a string here
they.can(EDIT, 'Article', author=user)

Combining Rules
^^^^^^^^^^^^^^^
You can (are encouraged to) combine similar rules on a single line:

.. code:: python

they.can((EDIT,READ,DELETE),(Article,Photo))

Combining Abilities
^^^^^^^^^^^^^^^^^^^

It is possible to define multiple abilites for the same resource. This is
particularly useful in combination with the ``cannot`` method

.. code:: python

they.can(MANAGE, ALL)
then.cannot(DELETE, ('USER', 'ACCOUNT'))

Checking Abilities
------------------
There are two main ways for checking for authorization. ``can`` (and its brother ``cannot``) and ``ensure``

* ``can`` returns a boolean
* ``ensure`` will raise an ``AccessDenied`` Exception

.. code:: python

from bouncer import can, ensure
from bouncer.constants import *

jonathan = User(name='jonathan',admin=False)

# can jonathan edit articles in general
can(jonathan, EDIT, Article)

# ensure jonathan edit articles in general -- otherwise we are going to throw an exception
ensure(jonathan, EDIT, Article)

article = Article(author=jonathan)

# can jonathan delete this specific article
can(jonathan, EDIT, article)

Decorating your User Model
~~~~~~~~~~~~~~~~~~~~~~~~~~
Optionally, you can add helper methods into your User model by using ``@authorization_target``

For example:

.. code:: python

from bouncer import authorization_target

@authorization_target
class User(object):

def __init__(self, **kwargs):
self.id = kwargs.get('id', 1)
self.name = kwargs.get('name', '')
self.admin = kwargs.get('admin', False)
pass

@property
def is_admin(self):
return self.admin

jonathan = User(name='jonathan',admin=False)
marc = User(name='marc',admin=False)

article = Article(author=jonathan)

print jonathan.can(EDIT,article) # True
print marc.can(EDIT,article) # False

Flask
-----

If you use Flask, I am currently working on a Flask extension – follow
its progress here: `flask-bouncer`_.

Questions / Issues
------------------

Feel free to ping me on twitter: `@tushman`_
or add issues or PRs at https://github.com/jtushman/bouncer

.. _flask-bouncer: https://github.com/jtushman/flask-bouncer
.. _@tushman: http://twitter.com/tushman