Package: django-keeper
django-keeperAuthorization library for Django, not depends on models.Won't depend on modelsWon't depend on datastoresWon't depend on Django's permission systemWon't depend on Django's User modelSupported versions:Python3.8Python 3.9Django 2.2Django 3.0Django 3.1Django 3.2Django 4.1Django 4.2Install$pipinstalldjango-keeperAnd add to INSTALLED_APPSINSTALLED_APPS=[...'keeper',]At A GlanceDeclarative permission mapping for models.fromdjango.confimportsettingsfromkeeper.securityimportAllowfromkeeper.operatorsimportEveryone,Authenticated,IsUserclassIssue(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 viewAutheticated requests to add commentsit's author to editThen, apply@keeperfor views.fromkeeper.viewsimportkeeper# Model Permissions@keeper('view',model=Issue,mapper=lambdarequest,issue_id:{'id':issue_id},)defissue_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 issueThe 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=lambdarequest,issue_id:{'id':issue_id},)defadd_comment(request,issue_id):...Global PermissionNot just for model permissionsdjango-keepercan handle global permissions.First, write class having__acl__method in models.py.classRoot:def__acl__(self):return[(Allow,Authenticated,'view_dashboard'),(Allow,Authenticated,'add_issue'),]It's not necessary to put it inmodels.py,
but easy to understand.And specify it in settings.KEEPER_GLOBAL_CONTEXT='myapp.models.Root'Then you can use global permission in views.
Simply just apply@keeperand permission names.@keeper('add_issue')defissue_list(request):""" View requires 'add_issue' permission of Root Context"""OperatorsOperators is justCallable[[HttpRequest], bool].
By default django-keeper has these operators:keeper.operators.Everyonekeeper.operators.Authenticatedkeeper.operators.IsUserkeeper.operators.StaffAlso you can create your own operators easily.fromkeeper.operatorsimportAuthenticated,OperatorclassIsIP(Operator):def__init__(self,ip):self.ip=ipdef__call__(self,request):returnrequest.META.get('REMOTE_ADDR')==self.ipclassBelongsTeam(Authenticated):def__init__(self,team,role):self.team=teamdef__call__(self,request):ifnotsuper().__call__(request):returnFalsereturnrequest.user.team==self.teamUse it in ACLclassArticle(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'),]Combining operatorsYou can use bitwise operators to combine multiple "Operators".classArticle(models.Model):def__acl__(self):return[(Allow,Authenticated()&IsIP(settings.COMPANY_IP_ADDRESS),'view'),]There operators can be useda & ba | ba ^ b~aOn Fail ActionsYou can change actions when requests can't pass ACLs.fromkeeper.viewsimportkeeper,login_required@keeper('view_articles',on_fail=login_required(),)defdashboard(request):...This view will behave just like@login_requireddecorator of Django
when requests don't have 'view' permission.Also you can use other actions.keeper.views.login_requiredkeeper.views.permission_deniedkeeper.views.not_foundkeeper.views.redirectUse in templateHandling permissions in templates is also supported.{%loadkeeper%}{%has_permissionissue'edit'ascan_edit%}{%ifcan_edit%}<a href="...">Edit</a>{%endif%}When checking global permission, usehas_global_permission.{%loadkeeper%}{%has_global_permission'add_issue'ascan_add_issue%}{%ifcan_add_issue%}<a href="...">New Issue</a>{%endif%}With Django CoreAdd the authentication backend:AUTHENTICATION_BACKENDS=('keeper.permissions.ObjectPermissionBackend','django.contrib.auth.backends.ModelBackend',)NowUser.has_permmethod will consider permissions of django-keeper.Alternativedjango-guardianIt depends on databasesNot way to handle global permissions, not just for a modeldjango-rulesBasiaclly, rules is used with Django's permissions, but keeper isn't (basiacally).rules doesn't support view decorators or mixins for it's "rules" system (for Django's permission, yes).FAQCan I filter models by using ACL?Not supported