Reputation: 3833
I'm adding some custom authorization to verify that logged in users have access to specific sections of my application. It's not pretty, but it works:
view_permissions = {
'admin_list': {
'school':{'userrole':['S','A'], 'usertype':[]},
'class':{'userrole':['S','A'], 'usertype':[]},
' ... '
},
'delete_object': { ... },
'edit_object': { ... },
}
}
def check_permissions(request, viewname, objecttype):
if(request.user.userrole in view_permissions[viewname][objecttype]['userrole'] or
request.user.usertype in view_permissions[viewname][objecttype]['usertype']
):
return True
else:
return False
def delete_object(request, objecttype, objectid):
# Redirect to home page if not authorized
if(not check_permissions(request, 'delete_object', objecttype)):
return redirect('wakemeup:index')
# Otherwise, continue processing
myobject.delete()
...
return admin_list(request, objecttype)
What I want to do is move the redirect
to be inside the check_permissions
function, something like this:
def check_permissions(request, viewname, objecttype):
if( <check permissions are valid> ):
pass # Authorized: Do nothing and continue with caller view logic
else:
return redirect('wakemeup:index') # Unauthorized: redirect to home
def delete_object(request, objecttype, objectid):
# Redirect to home page if not authorized
check_permissions(request, 'delete_object', objecttype))
The problem is that, the redirect inside the check_permissions
function doesn't do anything. It only redirects if I add a return
to the calling logic:
def delete_object(request, objecttype, objectid):
# Redirect to home page if not authorized
return check_permissions(request, 'delete_object', objecttype))
I'm guessing it has something to do with the nested function call returning its output all the way to the original caller. But is there a simple way I can get the redirect to work from within the check_permissions
function?
Updated function -- I have to access the request
object via args[0], but I can access my other variables via kwargs
. I guess it's because in the forms, the request object is just passed under-the-covers and not as an argument.
def check_perm(view):
viewname = view.__name__
def view_wrapper(*args, **kwargs):
objecttype = kwargs['objecttype']
myuser = args[0].user
if not (
myuser.userrole in view_permissions[viewname][objecttype]['userrole'] or
myuser.usertype in view_permissions[viewname][objecttype]['usertype']
):
# Invalid permission - redirect
return redirect('wakemeup:index')
# Valid permission - continue
return view(*args, **kwargs)
return view_wrapper
...
@check_perm
def delete_object(request, objecttype, objectid):
...
Upvotes: 1
Views: 237
Reputation: 1745
I think a function decorator is the perfect solution for this problem. The following allows you to check conditions (permissions), hijack the response with a redirect if necessary and if not, continue with the normal view response:
from django.shortcuts import redirect
def check_permissions(view):
view_name = view.__name__
def view_wrapper(*args, **kwargs):
# Check permissions here.
if False or False or True:
# Hijack response with a redirect if conditions not met.
return redirect('wakemeup:index')
# Conditions met, continue with normal response.
return view(*args, **kwargs)
return view_wrapper
@check_permissions
def delete_object(request, object_type, object_id):
# Your normal view...
return
Also, note the way it captures the view name. Much more dynamic in my opinion.
Upvotes: 3