Add class_has_permission decorator

This decorator adds permission for each
method of `aiohttp.web.View` class
This commit is contained in:
Vincent Maillol
2018-04-19 07:42:51 +02:00
parent cb1ca8a671
commit 2371a9574b
3 changed files with 176 additions and 3 deletions

View File

@@ -1,5 +1,6 @@
from .abc import AbstractAuthorizationPolicy, AbstractIdentityPolicy
from .api import (authorized_userid, forget, has_permission, is_anonymous,
from .api import (authorized_userid, forget, has_permission,
class_has_permission, is_anonymous,
login_required, permits, remember, setup)
from .cookies_identity import CookiesIdentityPolicy
from .session_identity import SessionIdentityPolicy
@@ -11,4 +12,4 @@ __all__ = ('AbstractIdentityPolicy', 'AbstractAuthorizationPolicy',
'CookiesIdentityPolicy', 'SessionIdentityPolicy',
'remember', 'forget', 'authorized_userid',
'permits', 'setup', 'is_anonymous',
'login_required', 'has_permission')
'login_required', 'has_permission', 'class_has_permission')

View File

@@ -145,7 +145,6 @@ def has_permission(
userid = await authorized_userid(request)
if userid is None:
raise web.HTTPUnauthorized
allowed = await permits(request, permission, context)
if not allowed:
raise web.HTTPForbidden
@@ -157,6 +156,41 @@ def has_permission(
return wrapper
def class_has_permission(permission_prefix, context=None):
"""Decorator that restrict access only for authorized users
with correct permissions for each method of a `aiohttp.web.View`
class.
The needed permission to perform:
- POST request is `.create` prefixed by `prefix`
- GET request is `.read` prefixed by `prefix`
- PATCH or PUT request is `.update` prefixed by `prefix`
- DELETE request is `.delete` prefixed by `prefix`
If user is not authorized - raises HTTPUnauthorized,
if user is authorized and does not have permission -
raises HTTPForbidden.
"""
def decorator(cls):
methods = {'post': 'create',
'get': 'read',
'put': 'update',
'patch': 'update',
'delete': 'delete'}
for method_name, permission in methods.items():
method = getattr(cls, method_name, None)
if method is not None:
decorator = has_permission(
'{}.{}'.format(permission_prefix, permission),
context)
setattr(cls, method_name, decorator(method))
return cls
return decorator
def setup(app, identity_policy, autz_policy):
assert isinstance(identity_policy, AbstractIdentityPolicy), identity_policy
assert isinstance(autz_policy, AbstractAuthorizationPolicy), autz_policy