I have a view set like this
class NeProjectsViewSet(viewsets.ViewSet):
def list(self, request,org_unique_id):
''' something '''
def create(self, request,org_unique_id):
''' something '''
def retrieve(self):
''' something '''
def update(self, request, pk):
''' something '''
def partial_update(self, request):
''' something '''
def destroy(self, request):
''' something '''
and i've a method like this
def check_session(self,request):
current_datetime = datetime.now()
if ('last_login' in request.session):
last = (current_datetime - datetime.strptime(request.session['last_login'], "%Y-%m-%d %H:%M:%S.%f")).seconds
if last > base.SESSION_IDLE_TIMEOUT:
del request.session['token']
raise ValueError('Session Expired')
else:
request.session['last_login'] = str(current_datetime)
return (request.session['token'] == request.META['HTTP_AUTHORIZATION'])
to validate session for every request, for that i need to call this method before every method in the viewset. I read somewhere writing custom decorator is better way, so how to implement custom decorator for my view set to check session for request
Assuming you are using DRF.
I think you are going in wrong direction. If this is part of your permission layer you should just add custom permission class to your viewset
http://www.django-rest-framework.org/api-guide/permissions/
from rest_framework import permissions
class ValidateSession(permissions.BasePermission):
"""
Validate session expiration
"""
def has_permission(self, request, view):
current_datetime = datetime.now()
if ('last_login' in request.session):
last = (current_datetime - datetime.strptime(request.session['last_login'], "%Y-%m-%d %H:%M:%S.%f")).seconds
if last > base.SESSION_IDLE_TIMEOUT:
del request.session['token']
return False
else:
request.session['last_login'] = str(current_datetime)
return (request.session['token'] == request.META['HTTP_AUTHORIZATION'])
And then add it like this
class NeProjectsViewSet(viewsets.ViewSet):
permission_classes = (ValidateSession,)
...
Assuming you're using plain django
from django.contrib.auth.mixins import AccessMixin
class ValidateSessionMixin(AccessMixin):
"""
Validate session
"""
def has_permission(self):
current_datetime = datetime.now()
request = self.request
if ('last_login' in request.session):
last = (current_datetime - datetime.strptime(request.session['last_login'], "%Y-%m-%d %H:%M:%S.%f")).seconds
if last > base.SESSION_IDLE_TIMEOUT:
del request.session['token']
return True
else:
request.session['last_login'] = str(current_datetime)
return (request.session['token'] == request.META['HTTP_AUTHORIZATION'])
def dispatch(self, request, *args, **kwargs):
if not self.has_permission():
return self.handle_no_permission()
return super(ValidateSessionMixin, self).dispatch(request, *args, **kwargs)
And apply this mixin like this
class NeProjectsViewSet(ValidateSessionMixin, viewsets.ViewSet):
...
Related
I have a decorator which does the same query as the function it's attached to. Is there a way to just pass the Queryset from the decorator so I don't have to run the query twice?
decorator.py
def is_wifi_author(func):
def wrapper(request, wifi_id, **kwargs):
wifi = get_object_or_404(Wifi, pk=wifi_id) # Queryset
# Is this correct?
if request.user != wifi.author:
return redirect('youshallnotpass')
return func(request, wifi_id, **kwargs)
return wrapper
views.py
#is_wifi_author
def edit(request, wifi_id):
# print(request)
wifi = get_object_or_404(Wifi, pk=wifi_id) # Same queryset
# The rest of the view
return render(request, 'app/template.html')
Yes, just checking if the user has access to edit the post. Any comments welcome.
Yes, it's possible by using kwargs:
def is_wifi_author(func):
def wrapper(request, wifi_id, **kwargs):
wifi = get_object_or_404(Wifi, pk=wifi_id) # Queryset
# Is this correct?
if request.user != wifi.author:
return redirect('youshallnotpass')
return func(request, wifi_id, wiki=wiki, **kwargs)
return wrapper
#is_wifi_author
def edit(request, wifi_id, wiki=None):
"""wiki argument is gonna be updated by the is_wifi_author decorator"""
print('Yeii, a wiki', wiki)
# The rest of the view
return render(request, 'app/template.html')
Though I think #Ubaid answer mentions a valid point.
Why use a decorator when you can simply do
wifi = get_object_or_404(Wifi, pk=wifi_id, author=request.user)
Block particular user for some specific time to using Django REST Throttling.
I have seen Django REST Throttling.
I don't want to use third-party packages.
Thanks in advance
I have found the solution after customized Django REST Throttling,
Its Blocking particular user after 3 login attempts (Block user_id that presents in my application).
Block IP address after 6 login attempts for anonymous user.
prevent.py:-
#!/usr/bin/python
from collections import Counter
from rest_framework.throttling import SimpleRateThrottle
from django.contrib.auth.models import User
class UserLoginRateThrottle(SimpleRateThrottle):
scope = 'loginAttempts'
def get_cache_key(self, request, view):
user = User.objects.filter(username=request.data.get('username'))
ident = user[0].pk if user else self.get_ident(request)
return self.cache_format % {
'scope': self.scope,
'ident': ident
}
def allow_request(self, request, view):
"""
Implement the check to see if the request should be throttled.
On success calls `throttle_success`.
On failure calls `throttle_failure`.
"""
if self.rate is None:
return True
self.key = self.get_cache_key(request, view)
if self.key is None:
return True
self.history = self.cache.get(self.key, [])
self.now = self.timer()
while self.history and self.history[-1] <= self.now - self.duration:
self.history.pop()
if len(self.history) >= self.num_requests:
return self.throttle_failure()
if len(self.history) >= 3:
data = Counter(self.history)
for key, value in data.items():
if value == 2:
return self.throttle_failure()
return self.throttle_success(request)
def throttle_success(self, request):
"""
Inserts the current request's timestamp along with the key
into the cache.
"""
user = User.objects.filter(username=request.data.get('username'))
if user:
self.history.insert(0, user[0].id)
self.history.insert(0, self.now)
self.cache.set(self.key, self.history, self.duration)
return True
view.py:-
from .prevent import UserLoginRateThrottle
....
....
....
class ObtainAuthToken(auth_views.ObtainAuthToken):
throttle_classes = (UserLoginRateThrottle,)/use this method here your login view
def post(self, request, *args, **kwargs):
....
....
Add some parameters in setting file
settings.py:-
# Django-rest-framework
REST_FRAMEWORK = {
...
...
...
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.UserRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'loginAttempts': '6/hr',
'user': '1000/min',
}
}
I want to make a decorators which prevents the user to see others profile but can see own profile. If the user has id passed in url as http://example.com/user/?id=5 i want to get the value id=5 in my django decorator. How can I get it any example ?
def admin_or_ownership_required(owner):
def check_admin_or_owner(user):
# pk = request.GET.get('pk', None)
# if pk is not None and pk == user.id:
# return True
if owner == 'Account':
if user.is_superuser or (user.is_active and (user.role == 'admin' or user.role == 'owner')):
return True
else:
return False
elif owner == 'User':
if user.is_superuser or (user.is_active and (user.role == 'admin' or user.role == 'owner')):
return True
else:
return False
else:
return False
return user_passes_test(check_admin_or_owner)
this is my view code
class AccountDetailView(DetailView):
template_name = 'api/account_detail.html'
model = Account
#method_decorator(admin_or_ownership_required('Account'))
def dispatch(self, *args, **kwargs):
return super(AccountDetailView, self).dispatch(*args, **kwargs)
How can I use the request argument in admin_or_ownershipl_required decorator
def check_login(method):
#functools.wraps(method)
def wrapper(request, *args, **kwargs):
if request.GET['id'] == request.user.id
# Give your redirect url
return method(request, *args, **kwargs)
return wrapper
You could use a mixin for your View, where you limit your case queryset, something like:
class MixinRestrictedAccount(object):
def get_queryset(self):
return Account.objects.filter(id=self.request.user.id)
class AccountDetailView(MixinRestrictedBox, DetailView):
[..]
Try to dump the value of kwargs, from there you can access the url parameters. for example :
if you have Url like :
/users/(?P<username>\w+)/$
you can access that value by kwargs parameter , that is passed in your decorator method. You can access that by:
kwargs.get("username")
If you want to access url parameters by GET method, then you can try like this :
request.GET.get("username")
for URL's like :
/users/?username=dominic
Thanks .
I have code that read like this to check if POST parameters are included on the request:
def login(request):
required_params = frozenset(('email', 'password'))
if required_params <= frozenset(request.POST):
# 'email' and 'password' are included in the POST request
# continue as normal
pass
else:
return HttpResponseBadRequest()
When the list of required POST parameters is big, this code gets messy. What I would like to do is something like:
#required_POST_params('email', 'password')
def login(request):
# 'email' and 'password' are here always!
pass
Then I'm confident that both 'email' and 'password' POST parameters are included in the request, because if not, the request would automatically return HttpResponseBadRequest().
Is there a way that Django allows me to do this, and if it doesn't, how can I do it by myself with a decorator?
You would need a custom decorator, but you can take require_http_methods as a base example:
def require_post_params(params):
def decorator(func):
#wraps(func, assigned=available_attrs(func))
def inner(request, *args, **kwargs):
if not all(param in request.POST for param in params):
return HttpResponseBadRequest()
return func(request, *args, **kwargs)
return inner
return decorator
Example usage:
#require_post_params(params=['email', 'password'])
def login(request):
# 'email' and 'password' are here always!
pass
FYI, require_http_methods source code.
i'm sharing my solution;
__author__ = 'yagmurs'
from copy import deepcopy
from rest_framework import status
from rest_framework.response import Response
def require_params(*params):
def decorator(fn):
def wrapped_function(request, *args, **kwargs):
"""
Decorator for django rest service to meet both GET and POST request
"""
error = deepcopy(REQUEST_INVALID_400)
is_param_missing = False
for param in params:
if not get_param_from_request(param, request):
error['result_message'] += param + ", "
is_param_missing = True
if is_param_missing:
error['result_message'] = error['result_message'][:-2]
return Response(error, status=status.HTTP_400_BAD_REQUEST)
else:
return fn(request, *args, **kwargs)
return wrapped_function
return decorator
def get_param_from_request(param, request):
if request.method == 'POST':
return request.data.get(param)
else:
return request.query_params.get(param)
Try with this.
Instead of require.POST(), try with require.POST('email', 'password').
I have some problem related to that I am trying to implement a middleware which detects the whether the authenticated user is inactive for 5 seconds. I have wrote below Python module to do this job but It seems it is not works well. I found two reason ;
One of them is ; I can not redirect the user to the home page correctly
; Middleware is not change session key correctly
I have not found that how I can solve this problems. I will show what I have done to the below as two part.
First part ; middleware.py
class TimeOut:
#csrf_exempt
def process_request(self, request):
try :
if request.session['isA'] == False:
return #redirect(reverse("homePage_view"))
except KeyError:
request.session['isA'] = False
return
try :
passT = datetime.now() - request.session['Time']
if passT > timedelta( 0, settings.SESSION_COOKIE, 0):
request.session['isA'] = False
del request.session['Time']
return
except KeyError:
pass
request.session['Time'] = datetime.now()
Second part ; settings.py
SESSION_COOKIE = 5
MIDDLEWARE_CLASSES = (
'home.middleware.TimeOut',
)
EDIT: I have mistakenly wrote other class. I have changed the name as TimeOut
Is this the one you are talking:
class AutoLogout:
def process_request(self, request):
if not request.user.is_authenticated() :
return HttpResponseRedirect(reverse('app_name:url_name'))
try:
if datetime.now() - request.session['last_touch'] > timedelta( 0, settings.AUTO_LOGOUT_DELAY * 60, 0):
auth.logout(request)
del request.session['last_touch']
return HttpResponseRedirect(reverse('app_name:url_name'))
except KeyError:
pass
request.session['last_touch'] = datetime.now()
decorators.py
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
def login_check(view_func):
def _wrapped_view_func(request, *args, **kwargs):
if not request.user.is_authenticated:
//return to home page url
return HttpResponseRedirect(reverse('app_name:url_name'))
return view_func(request, *args, **kwargs)
return _wrapped_view_func
After you create decorators.py, update your view like this:
from app_name.decorators import login_check
#login_check
def view_name(request):
.........
The user will not be allow to go to that page if not authenticated.