Permissions¶
Main permissions goal is to often check if client has access to read/update/delete views. Implementation of django-is-core permissions system is very similar to DRF permissions. Base permission class is:
-
class
is_core.auth.permissions.
BasePermission
¶ Objects define structure of all permissions instances.
-
has_permission
(name, request, view, obj=None)¶ Method must be implemented for every permission object and should return True if all requirements was fulfilled to grant access to the client. First parameter name defines name of the wanted access, request is Django request object, view is Django view or REST resource and optional parameter obj is obj related with the given request.
-
Predefined permissions¶
-
class
is_core.auth.permissions.
PermissionsSet
¶ PermissionSet
contains a set of permissions identified by name. Permission is granted if permission with the given name grants the access. Finally if no permission with the given name is foundFalse
is returned.
-
class
is_core.auth.permissions.
IsAuthenticated
¶ Grants permission if user is authenticated and is active.
-
class
is_core.auth.permissions.
IsSuperuser
¶ Grants permission if user is authenticated, is active and is superuser.
-
class
is_core.auth.permissions.
IsAdminUser
¶ Grants permission if user is authenticated, is active and is staff.
-
class
is_core.auth.permissions.
AllowAny
¶ Grants permission every time.
-
class
is_core.auth.permissions.
CoreAllowed
¶ Grants permission if core (related with the view) permission selected according to the name grants the access.
-
class
is_core.auth.permissions.
CoreReadAllowed
¶ Grants permission if core read permission grant access.
-
class
is_core.auth.permissions.
CoreCreateAllowed
¶ Grants permission if core create permission grant access.
-
class
is_core.auth.permissions.
CoreUpdateAllowed
¶ Grants permission if core update permission grant access.
-
class
is_core.auth.permissions.
CoreDeleteAllowed
¶ Grants permission if core delete permission grant access.
-
class
is_core.auth.permissions.
AndPermission
¶ AndPermission
is only helper for joining more permissions withAND
operator.AndPermission
init method accepts any number of permission instances and returnsTrue
if every inner permission returnsTrue
:AndPermission(IsAdminUser(), IsSuperuser(), IsAuthenticated())
Because this style of implementation is badly readable you can join permissions
&
, the result will be the same:IsAdminUser() & IsSuperuser() & IsAuthenticated()
-
class
is_core.auth.permissions.
OrPermission
¶ OrPermission
is same asAndPermission
but permissions are joined withOR
operator.OrPermission
returnsTrue
if any inner permission returnsTrue
. Again you can use joining with|
operator:OrPermission(IsAdminUser(), IsSuperuser(), IsAuthenticated()) IsAdminUser() | IsSuperuser() | IsAuthenticated()
Whole three permissions
Custom permission¶
If you want to implement custom permission, you only must create subclass of is_core.auth.permissions.BasePermission
and implement has_permission
method.
Core permissions¶
As an example of how to define core permissions we use model core of User object:
from django.contrib.auth.models import User
from is_core.auth.permissions import IsSuperuser
from is_core.main import UIRESTModelISCore
class UserISCore(UIRESTModelISCore):
model = User
permission = IsSuperuser()
Now only a superuser has access to the User core. But this solution is a little bit dangerous, because there is no validated permission name and we only want create,read, update and delete permission names. Better solution is to use is_core.auth.permissions.PermissionsSet
:
from django.contrib.auth.models import User
from is_core.auth.permissions import PermissionsSet, IsSuperuser
from is_core.main import UIRESTModelISCore
class UserISCore(UIRESTModelISCore):
model = User
permission = PermissionsSet(
add=IsSuperuser(),
read=IsSuperuser(),
update=IsSuperuser(),
delete=IsSuperuser(),
)
Because writing too much code can lead to typos you can use default_permission
attribute from which is automatically generated permission
the result will be same as in previous example:
from django.contrib.auth.models import User
from is_core.auth.permissions import IsSuperuser
from is_core.main import UIRESTModelISCore
class UserISCore(UIRESTModelISCore):
model = User
default_permission = IsSuperuser()
But if you want to disable for example deleting model instances the delete permission will not be added to the permission set:
from django.contrib.auth.models import User
from is_core.auth.permissions import IsSuperuser
from is_core.main import UIRESTModelISCore
class UserISCore(UIRESTModelISCore):
model = User
default_permission = IsSuperuser()
can_delete = False
the attribute permission will be now:
permission = PermissionsSet(
add=IsSuperuser(),
read=IsSuperuser(),
update=IsSuperuser(),
)
You can use operator joining for using more permission types:
from django.contrib.auth.models import User
from is_core.auth.permissions import IsSuperuser, IsAdminUser
from is_core.main import UIRESTModelISCore
class UserISCore(UIRESTModelISCore):
model = User
default_permission = IsSuperuser() & IsAdminUser()
For some cases is necessary update permissions in a class mixin for this purpose you can use method ``_init_permission(permission)`:
from is_core.auth.permissions import IsSuperuser, IsAdminUser
from is_core.main import UIRESTModelISCore
class HistoryISCoreMixin:
def _init_permission(self, permission):
permission = super()._init_permission(permission)
permission.set('history', IsSuperuser())
return permission
class UserISCore(UIRESTModelISCore):
model = User
permission = PermissionsSet(
add=IsAdminUser(),
read=IsAdminUser(),
update=IsAdminUser(),
delete=IsAdminUser(),
)
View permissions¶
View permissions are used in the same way as core permissions:
from is_core.auth.permissions import IsSuperuser
from is_core.generic_views.form_views import ReadonlyDetailModelFormView
class UserReadonlyDetailModelFormView(ReadonlyDetailModelFormView):
permission = IsSuperuser()
Again you can set permissions according to names. For view permissions the names are HTTP method names:
from is_core.auth.permissions import PermissionsSet, IsSuperuser
from is_core.generic_views.form_views import DetailModelFormView
class UserDetailModelFormView(DetailModelFormView):
permission = PermissionsSet(
post=IsSuperuser(),
get=IsSuperuser()
)
By default core views get access permissions from core. For example detail view permissions are set this way:
from is_core.auth.permissions import PermissionsSet, CoreReadAllowed, CoreUpdateAllowed
from is_core.generic_views.form_views import DetailModelFormView
class UserDetailModelFormView(DetailModelFormView):
permission = PermissionsSet(
post=CoreUpdateAllowed(),
get=CoreReadAllowed()
)
If you want to have edit view accessible only if user is allowed to modify an object in core permissions. You can use very similar implementation:
from is_core.auth.permissions import PermissionsSet, CoreUpdateAllowed
from is_core.generic_views.form_views import DetailModelFormView
class UserDetailModelFormView(DetailModelFormView):
permission = PermissionsSet(
post=CoreUpdateAllowed(),
get=CoreUpdateAllowed()
)
REST permissions¶
For the REST classes permissions you can use the same rules. The only difference is that there are more types of permissions because REST resource fulfills two functions - serializer and view (HTTP requests):
from is_core.rest.resource import RESTObjectPermissionsMixin
class RESTModelCoreResourcePermissionsMixin(RESTObjectPermissionsMixin):
permission = PermissionsSet(
# HTTP permissions
head=CoreReadAllowed(),
options=CoreReadAllowed(),
post=CoreCreateAllowed(),
get=CoreReadAllowed(),
put=CoreUpdateAllowed(),
patch=CoreUpdateAllowed(),
delete=CoreDeleteAllowed(),
# Serializer permissions
create_obj=CoreCreateAllowed(),
read_obj=CoreReadAllowed(),
update_obj=CoreUpdateAllowed(),
delete_obj=CoreDeleteAllowed()
)
Check permissions¶
View/resource¶
If you want to check your custom permission in view or REST resource you can use method has_permission(name, obj=None)
as an example we can use method is_readonly
in th form view (form is readonly only if post permission returns False
):
def is_readonly(self):
return not self.has_permission('post')
Because some permissions require obj parameter all views that inherit from is_core.generic_views.mixins.GetCoreObjViewMixin
has automatically added objects to the permission check.
Core¶
Sometimes you need to check permission in the core. But there is no view instance and you will have to create it. For better usability you can check permissions via view patterns, as an example we can use method get_list_actions
which return edit action only if user has permission to update an object:
def get_list_actions(self, request, obj):
list_actions = super(UIRESTModelISCore, self).get_list_actions(request, obj)
detail_pattern = self.ui_patterns.get('detail')
if detail_pattern and detail_pattern.has_permission('get', request, obj=obj):
return [
WebAction(
'detail-{}'.format(self.get_menu_group_pattern_name()), _('Detail'),
'edit' if detail_pattern.has_permission('post', request, obj=obj) else 'detail'
)
] + list(list_actions)
else:
return list_actions
Pattern method has_permission(name, request, obj=None, **view_kwargs)
can be used with more ways. By default is view_kwargs
get from request kwargs. If you can change it you can use method kwargs parameters. Parameter obj
can be used for save system performance because object needn’t be loaded from database again:
detail_pattern = self.ui_patterns.get('detail')
detail_pattern.has_permission('get', request) # object id is get from request.kwargs
detail_pattern.has_permission('get', request, id=obj.pk) # request.kwargs "id" is overridden with obj.pk
detail_pattern.has_permission('get', request, obj=obj) # saves db queryes because object needn't be loaded from database