Skip to content

Commit c8c47c9

Browse files
authored
Merge pull request #6 from actioncy/config-enforcer
automatically initialize adapter + enforcer
2 parents a0d2228 + c5fee8c commit c8c47c9

5 files changed

Lines changed: 101 additions & 21 deletions

File tree

README.md

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,38 +28,40 @@ Based on [Officially Supported Databases](https://docs.djangoproject.com/en/3.0/
2828
pip install casbin-django-orm-adapter
2929
```
3030

31-
Add `casbin_adapter` to your `INSTALLED_APPS`
31+
Add `casbin_adapter.apps.CasbinAdapterConfig` to your `INSTALLED_APPS`
3232

3333
```python
34+
# settings.py
35+
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
36+
3437
INSTALLED_APPS = [
3538
...
36-
'casbin_adapter',
39+
'casbin_adapter.apps.CasbinAdapterConfig',
3740
...
3841
]
42+
43+
CASBIN_MODEL = os.path.join(BASE_DIR, 'casbin.conf')
3944
```
4045

41-
To run schema migration, execute `python manage.py migrate casbin_adapter
46+
To run schema migration, execute `python manage.py migrate casbin_adapter`
4247

4348
## Simple Example
4449

4550
```python
46-
import casbin
47-
from casbin_adapter.adapter import Adapter
48-
49-
adapter = Adapter()
50-
51-
e = casbin.Enforcer('path/to/model.conf', adapter, True)
52-
53-
sub = "alice" # the user that wants to access a resource.
54-
obj = "data1" # the resource that is going to be accessed.
55-
act = "read" # the operation that the user performs on the resource.
56-
57-
if e.enforce(sub, obj, act):
58-
# permit alice to read data1casbin_django_orm_adapter
59-
pass
60-
else:
61-
# deny the request, show an error
62-
pass
51+
# views.py
52+
from casbin_adapter.enforcer import enforcer
53+
54+
def hello(request):
55+
sub = "alice" # the user that wants to access a resource.
56+
obj = "data1" # the resource that is going to be accessed.
57+
act = "read" # the operation that the user performs on the resource.
58+
59+
if e.enforce(sub, obj, act):
60+
# permit alice to read data1casbin_django_orm_adapter
61+
pass
62+
else:
63+
# deny the request, show an error
64+
pass
6365
```
6466

6567
### Getting Help

casbin_adapter/adapter.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from django.conf import settings
12
from casbin import persist
23

34
from .models import CasbinRule

casbin_adapter/apps.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
from django.apps import AppConfig
2+
from django.db import connection
3+
from django.db.utils import OperationalError, ProgrammingError
24

35

46
class CasbinAdapterConfig(AppConfig):
57
name = 'casbin_adapter'
8+
9+
def ready(self):
10+
from .enforcer import initialize_enforcer
11+
initialize_enforcer()
12+

casbin_adapter/enforcer.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from django.conf import settings
2+
from django.db import connection
3+
from django.db.utils import OperationalError, ProgrammingError
4+
5+
from casbin import Enforcer
6+
7+
from .adapter import Adapter
8+
9+
10+
class ProxyEnforcer(Enforcer):
11+
_initialized = False
12+
13+
def __init__(self, *args, **kwargs):
14+
if self._initialized:
15+
super().__init__(*args, **kwargs)
16+
17+
def _load(self):
18+
if self._initialized == False:
19+
self._initialized = True
20+
model = getattr(settings, 'CASBIN_MODEL')
21+
enable_log = getattr(settings, 'CASBIN_LOG_ENABLED', False)
22+
adapter = Adapter()
23+
24+
super().__init__(model, adapter, enable_log)
25+
26+
watcher = getattr(settings, 'CASBIN_WATCHER', None)
27+
if watcher:
28+
self.set_watcher(watcher)
29+
30+
role_manager = getattr(settings, 'CASBIN_ROLE_MANAGER', None)
31+
if role_manager:
32+
self.set_role_manager(role_manager)
33+
34+
def __getattribute__(self, name):
35+
safe_methods = ['__init__', '_load', '_initialized']
36+
if not super().__getattribute__('_initialized') and name not in safe_methods:
37+
initialize_enforcer()
38+
if not super().__getattribute__('_initialized'):
39+
raise Exception((
40+
"Calling enforcer attributes before django registry is ready. "
41+
"Prevent making any calls to the enforcer on import/startup"
42+
))
43+
44+
return super().__getattribute__(name)
45+
46+
47+
enforcer = ProxyEnforcer()
48+
49+
50+
def initialize_enforcer():
51+
try:
52+
with connection.cursor() as cursor:
53+
cursor.execute(
54+
"""
55+
SELECT app, name applied FROM django_migrations
56+
WHERE app = 'casbin_adapter' AND name = '0001_initial';
57+
"""
58+
)
59+
row = cursor.fetchone()
60+
if row:
61+
enforcer._load()
62+
except (OperationalError, ProgrammingError):
63+
pass
64+

tests/settings.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import os
2+
3+
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4+
15
SECRET_KEY = 'not-a-production-secret'
26

37
INSTALLED_APPS = [
@@ -7,7 +11,7 @@
711
"django.contrib.sessions",
812
"django.contrib.messages",
913
"django.contrib.staticfiles",
10-
"casbin_adapter",
14+
"casbin_adapter.apps.CasbinAdapterConfig",
1115
"tests",
1216
]
1317

@@ -37,3 +41,5 @@
3741
]
3842

3943
DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}}
44+
45+
CASBIN_MODEL = os.path.join(BASE_DIR, 'tests', 'rbac_model.conf')

0 commit comments

Comments
 (0)