Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 22 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,38 +28,40 @@ Based on [Officially Supported Databases](https://docs.djangoproject.com/en/3.0/
pip install casbin-django-orm-adapter
```

Add `casbin_adapter` to your `INSTALLED_APPS`
Add `casbin_adapter.apps.CasbinAdapterConfig` to your `INSTALLED_APPS`

```python
# settings.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

INSTALLED_APPS = [
...
'casbin_adapter',
'casbin_adapter.apps.CasbinAdapterConfig',
...
]

CASBIN_MODEL = os.path.join(BASE_DIR, 'casbin.conf')
```

To run schema migration, execute `python manage.py migrate casbin_adapter
To run schema migration, execute `python manage.py migrate casbin_adapter`

## Simple Example

```python
import casbin
from casbin_adapter.adapter import Adapter

adapter = Adapter()

e = casbin.Enforcer('path/to/model.conf', adapter, True)

sub = "alice" # the user that wants to access a resource.
obj = "data1" # the resource that is going to be accessed.
act = "read" # the operation that the user performs on the resource.

if e.enforce(sub, obj, act):
# permit alice to read data1casbin_django_orm_adapter
pass
else:
# deny the request, show an error
pass
# views.py
from casbin_adapter.enforcer import enforcer

def hello(request):
sub = "alice" # the user that wants to access a resource.
obj = "data1" # the resource that is going to be accessed.
act = "read" # the operation that the user performs on the resource.

if e.enforce(sub, obj, act):
# permit alice to read data1casbin_django_orm_adapter
pass
else:
# deny the request, show an error
pass
```

### Getting Help
Expand Down
1 change: 1 addition & 0 deletions casbin_adapter/adapter.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.conf import settings
from casbin import persist

from .models import CasbinRule
Expand Down
7 changes: 7 additions & 0 deletions casbin_adapter/apps.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
from django.apps import AppConfig
from django.db import connection
from django.db.utils import OperationalError, ProgrammingError


class CasbinAdapterConfig(AppConfig):
name = 'casbin_adapter'

def ready(self):
from .enforcer import initialize_enforcer
initialize_enforcer()

64 changes: 64 additions & 0 deletions casbin_adapter/enforcer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from django.conf import settings
from django.db import connection
from django.db.utils import OperationalError, ProgrammingError

from casbin import Enforcer

from .adapter import Adapter


class ProxyEnforcer(Enforcer):
_initialized = False

def __init__(self, *args, **kwargs):
if self._initialized:
super().__init__(*args, **kwargs)

def _load(self):
if self._initialized == False:
self._initialized = True
model = getattr(settings, 'CASBIN_MODEL')
enable_log = getattr(settings, 'CASBIN_LOG_ENABLED', False)
adapter = Adapter()

super().__init__(model, adapter, enable_log)

watcher = getattr(settings, 'CASBIN_WATCHER', None)
if watcher:
self.set_watcher(watcher)

role_manager = getattr(settings, 'CASBIN_ROLE_MANAGER', None)
if role_manager:
self.set_role_manager(role_manager)

def __getattribute__(self, name):
safe_methods = ['__init__', '_load', '_initialized']
if not super().__getattribute__('_initialized') and name not in safe_methods:
initialize_enforcer()
if not super().__getattribute__('_initialized'):
raise Exception((
"Calling enforcer attributes before django registry is ready. "
"Prevent making any calls to the enforcer on import/startup"
))

return super().__getattribute__(name)


enforcer = ProxyEnforcer()


def initialize_enforcer():
try:
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT app, name applied FROM django_migrations
WHERE app = 'casbin_adapter' AND name = '0001_initial';
"""
)
row = cursor.fetchone()
if row:
enforcer._load()
except (OperationalError, ProgrammingError):
pass

8 changes: 7 additions & 1 deletion tests/settings.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

SECRET_KEY = 'not-a-production-secret'

INSTALLED_APPS = [
Expand All @@ -7,7 +11,7 @@
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"casbin_adapter",
"casbin_adapter.apps.CasbinAdapterConfig",
"tests",
]

Expand Down Expand Up @@ -37,3 +41,5 @@
]

DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}}

CASBIN_MODEL = os.path.join(BASE_DIR, 'tests', 'rbac_model.conf')