Authorization library for Django, with ACL, not depends on models.
Project description
# django-keeper
Authorization library for Django, not depends on models.
* Won't depend on models
* Won't save assignments/permissions into datastores
Supported versions:
* Python 3.5
* Python 3.6
* Django 1.10
* Django 1.11
* Django 2.0
## Install
```bash
$ pip install django-keeper
```
And add to INSTALLED_APPS
```python
INSTALLED_APPS = [
...
'keeper',
]
```
## At A Glance
Declarative permission mapping for models.
```python
from django.conf import settings
from keeper.security import Allow
from keeper.operators import Everyone, Authenticated, IsUser
class Issue(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL)
...
def __acl__(self):
return [
(Allow, Everyone, 'view'),
(Allow, Authenticated, 'add_comment'),
(Allow, IsUser(self.author), 'edit'),
]
```
Instances of model allow:
* Every requests to view
* Autheticated requests to add comments
* it's author to edit
Then, apply `@keeper` for views.
```python
from keeper.views import keeper
# Model Permissions
@keeper(
'view',
model=Issue,
mapper=lambda request, issue_id: {'id': issue_id},
)
def issue_detail(request, issue_id):
""" View requires 'view' permission of Issue model
* An issue object will be retrieved
* keeper will check whether the rquests has 'view' permission for the issue
The third argument function can return keyword argument to retrieve the issue object.
"""
request.k_context # Will be instance of the issue object
...
@keeper(
'add_comment',
model=Issue,
mapper=lambda request, issue_id: {'id': issue_id},
)
def add_comment(request, issue_id):
...
```
## Global Permission
Not just for model permissions `django-keeper` can handle global permissions.
First, write class having `__acl__` method in models.py.
```python
class Root:
def __acl__(self):
return [
(Allow, Authenticated, 'view_dashboard'),
(Allow, Authenticated, 'add_issue'),
]
```
It's not necessary to put it in `models.py`,
but easy to understand.
And specify it.
```python
KEEPER_GLOBAL_CONTEXT = myapp.models.Root'
```
Then you can use global permission in views.
Simply just apply `@keeper` and permission names.
```python
@keeper('add_issue')
def issue_list(request):
""" View requires 'add_issue' permission of Root Context
"""
```
## Operators
Operators is just `Callable[[HttpRequest], bool]`.
By default django-keeper has these operators:
* `keeper.operators.Everyone`
* `keeper.operators.Authenticated`
* `keeper.operators.IsUser`
* `keeper.operators.Staff`
Also you can create your own operators easily.
```python
from keeper.operators import Authenticated
class IsIP:
def __init__(self, ip):
self.ip = ip
def __call__(self, request):
return request.META.get('REMOTE_ADDR') == self.ip
class BelongsTeam(Authenticated):
def __init__(self, team, role):
self.team = team
def __call__(self, request):
if not super().__call__(request):
return False
return request.user.team == self.team
```
Use it in ACL
```python
class Article(models.Model):
team = models.ForeignKey(Team)
def __acl__(self):
return [
(Allow, Everyone, 'view'),
(Allow, BelongsTeam(self.team), 'edit'),
(Allow, IsIP(settings.COMPANY_IP_ADDRESS), 'edit'),
]
```
## On Fail Actions
You can change actions when requests can't pass ACLs.
```python
from keeper.views import keeper, login_required
@keeper(
'view_articles',
on_fail=login_required(),
)
def dashboard(request):
...
```
This view will behave just like `@login_required` decorator of Django
when requests don't have 'view' permission.
Also you can use other actions.
* `keeper.views.login_required`
* `keeper.views.permission_denied`
* `keeper.views.not_found`
* `keeper.views.redirect`
## Use in template
Handling permissions in templates is also supported.
```django
{% load keeper %}
{% has_permission issue 'edit' as can_edit %}
{% if can_edit %}
<a href="...">Edit</a>
{% endif %}
```
When checking global permission, use `has_global_permission`.
```django
{% load keeper %}
{% has_global_permission 'add_issue' as can_add_issue %}
{% if can_add_issue %}
<a href="...">New Issue</a>
{% endif %}
```
## With Django Core
Add the authentication backend:
```python
AUTHENTICATION_BACKENDS = (
'keeper.permissions.ObjectPermissionBackend',
'django.contrib.auth.backends.ModelBackend',
)
```
Now `User.has_perm` method will consider permissions of django-keeper.
## Alternative
* [django-guardian](https://github.com/django-guardian/django-guardian)
* It depends on databases
* Not way to handle global permissions, not just for a model
* [django-rules](https://github.com/dfunckt/django-rules)
## FAQ
* Can I filter models by using ACL?
* Not supported
Authorization library for Django, not depends on models.
* Won't depend on models
* Won't save assignments/permissions into datastores
Supported versions:
* Python 3.5
* Python 3.6
* Django 1.10
* Django 1.11
* Django 2.0
## Install
```bash
$ pip install django-keeper
```
And add to INSTALLED_APPS
```python
INSTALLED_APPS = [
...
'keeper',
]
```
## At A Glance
Declarative permission mapping for models.
```python
from django.conf import settings
from keeper.security import Allow
from keeper.operators import Everyone, Authenticated, IsUser
class Issue(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL)
...
def __acl__(self):
return [
(Allow, Everyone, 'view'),
(Allow, Authenticated, 'add_comment'),
(Allow, IsUser(self.author), 'edit'),
]
```
Instances of model allow:
* Every requests to view
* Autheticated requests to add comments
* it's author to edit
Then, apply `@keeper` for views.
```python
from keeper.views import keeper
# Model Permissions
@keeper(
'view',
model=Issue,
mapper=lambda request, issue_id: {'id': issue_id},
)
def issue_detail(request, issue_id):
""" View requires 'view' permission of Issue model
* An issue object will be retrieved
* keeper will check whether the rquests has 'view' permission for the issue
The third argument function can return keyword argument to retrieve the issue object.
"""
request.k_context # Will be instance of the issue object
...
@keeper(
'add_comment',
model=Issue,
mapper=lambda request, issue_id: {'id': issue_id},
)
def add_comment(request, issue_id):
...
```
## Global Permission
Not just for model permissions `django-keeper` can handle global permissions.
First, write class having `__acl__` method in models.py.
```python
class Root:
def __acl__(self):
return [
(Allow, Authenticated, 'view_dashboard'),
(Allow, Authenticated, 'add_issue'),
]
```
It's not necessary to put it in `models.py`,
but easy to understand.
And specify it.
```python
KEEPER_GLOBAL_CONTEXT = myapp.models.Root'
```
Then you can use global permission in views.
Simply just apply `@keeper` and permission names.
```python
@keeper('add_issue')
def issue_list(request):
""" View requires 'add_issue' permission of Root Context
"""
```
## Operators
Operators is just `Callable[[HttpRequest], bool]`.
By default django-keeper has these operators:
* `keeper.operators.Everyone`
* `keeper.operators.Authenticated`
* `keeper.operators.IsUser`
* `keeper.operators.Staff`
Also you can create your own operators easily.
```python
from keeper.operators import Authenticated
class IsIP:
def __init__(self, ip):
self.ip = ip
def __call__(self, request):
return request.META.get('REMOTE_ADDR') == self.ip
class BelongsTeam(Authenticated):
def __init__(self, team, role):
self.team = team
def __call__(self, request):
if not super().__call__(request):
return False
return request.user.team == self.team
```
Use it in ACL
```python
class Article(models.Model):
team = models.ForeignKey(Team)
def __acl__(self):
return [
(Allow, Everyone, 'view'),
(Allow, BelongsTeam(self.team), 'edit'),
(Allow, IsIP(settings.COMPANY_IP_ADDRESS), 'edit'),
]
```
## On Fail Actions
You can change actions when requests can't pass ACLs.
```python
from keeper.views import keeper, login_required
@keeper(
'view_articles',
on_fail=login_required(),
)
def dashboard(request):
...
```
This view will behave just like `@login_required` decorator of Django
when requests don't have 'view' permission.
Also you can use other actions.
* `keeper.views.login_required`
* `keeper.views.permission_denied`
* `keeper.views.not_found`
* `keeper.views.redirect`
## Use in template
Handling permissions in templates is also supported.
```django
{% load keeper %}
{% has_permission issue 'edit' as can_edit %}
{% if can_edit %}
<a href="...">Edit</a>
{% endif %}
```
When checking global permission, use `has_global_permission`.
```django
{% load keeper %}
{% has_global_permission 'add_issue' as can_add_issue %}
{% if can_add_issue %}
<a href="...">New Issue</a>
{% endif %}
```
## With Django Core
Add the authentication backend:
```python
AUTHENTICATION_BACKENDS = (
'keeper.permissions.ObjectPermissionBackend',
'django.contrib.auth.backends.ModelBackend',
)
```
Now `User.has_perm` method will consider permissions of django-keeper.
## Alternative
* [django-guardian](https://github.com/django-guardian/django-guardian)
* It depends on databases
* Not way to handle global permissions, not just for a model
* [django-rules](https://github.com/dfunckt/django-rules)
## FAQ
* Can I filter models by using ACL?
* Not supported
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
django-keeper-0.1.9.tar.gz
(6.0 kB
view hashes)
Built Distribution
Close
Hashes for django_keeper-0.1.9-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5102061b632c540e6fc2dd38044a989b4bab072292e5fd6e5e20b9f817bf0e5a |
|
MD5 | 40aca900d7bd7904ee842511cb4aa63f |
|
BLAKE2b-256 | e75304fbd8f3617834da88cab4dee46c6cf12e47d5413dc55ca121abb272a29a |