I'm having a KeyError issue when trying to access something from flask.session and I'm questioning my implementation.
Essentially, I have a PUT request that looks something like this
def auth():
flask.session["access"] = "Admin"
blueprint.before_request(auth)
def put(...):
...
if flask.session["access"] == "Admin":
do_something_cool()
I'm getting a KeyError issue here and I suspect does it have something to do with the usage of blueprint?
Thanks
flask.session is not available outside of a request context. You are missing a decorator to register your view:
import flask
bp = flask.Blueprint('auth', 'auth')
#bp.before_request
def auth(): flask.session['access'] = 'Admin'
#bp.route('/something')
def put():
if flask.session['access'] == 'Admin': do_something_cool()
Related
I am writting an API in Django Rest Framework. I am using viewsets however regular methods create() and update() do not do it for me and I have to rewrite them.
Suppose that I need to do just one check to test if creation of an instance is legit, do I still have to rewrite the whole create function?
Currently I have this:
class LocationViewSet(viewsets.ModelViewSet):
permission_classes = (IsAuthenticated,)
serializer_class = LocationSerializer
def create(self, request, *args, **kwargs):
user = request.user
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
if user.can_create_location():
serializer.save()
return Response(serializer.data)
else:
raise exceptions.PermissionDenied('You dont have permission to create this.')
Instead of rewritting the whole thing, is it possible to somehow use inheritance and do something like this?
class LocationViewSet(viewsets.ModelViewSet):
permission_classes = (IsAuthenticated,)
serializer_class = LocationSerializer
def create(self, request, *args, **kwargs):
user = request.user
if user.can_create_location():
return super().create(self, request, *args, **kwargs)
else:
raise exceptions.PermissionDenied('You dont have permission to create this.')
The above does not work as I get this error. I feel like this should be possible to do, but I don't know how. Thanks for your help!
AttributeError at /api/0/location
LocationViewSet' object has no attribute 'data'
Request Method: POST
Request URL: http://127.0.0.1:8000/api/0/location
Django Version: 2.1.7
Yes, it does work, and you're doing it almost correctly... as per your error: the function is trying to access LocationViewSet.data as you're passing self in the first argument, change that call to:
super().create(request, *args, **kwargs)
Python standard docs has some info on super() and a link to a more in depth explanation.
I working on a simple mvc application where I have to submit forms with ajax. Then I create a class with purpose to manage all requests from specific module
class Produto(View):
template_name = 'produto/index.html'
def get(self, request):
context = {
'modulos': CELLO_APPS,
'modulo': 'Produtos'
}
return render(request, self.template_name, context)
def post(self, request):
if request.is_ajax() and request.method == "POST":
return JsonResponse({'FOO': 'BAR'})
else:
raise Http404
this looks pretty logical to me, but it doesn't work and raise an error
missing 1 required positional argument: 'request'
the only way I could solve this problem was setting post method as static
class Produto(View):
template_name = 'produto/index.html'
def get(self, request):
context = {
'modulos': CELLO_APPS,
'modulo': 'Produtos'
}
return render(request, self.template_name, context)
def post(request):
if request.is_ajax() and request.method == "POST":
return JsonResponse({'FOO': 'BAR'})
else:
raise Http404
So I have two doubts:
1- How can I create a single class with many functions accessible by ajax?
2- Would be this the best or recommended way to manage those views? (Considering this application can grow a lot in the future)
Edit.
Here follows my urls.py
urlpatterns = [
url(r'^inserir', Produto.inserir, name='produto_inserir'),
url(r'^$', Produto.as_view(), name='cliente'),
]
This is my view:
class PostListByUsername(generics.ListAPIView):
serializer_class = PostSerializer
permission_classes = (IsAuthenticated, IsLikeOrOwnerDeleteOrReadOnly, IsFromSameLocation,)
def get_queryset(self):
username = self.kwargs['username']
user = User.objects.get(username=username)
return Post.objects.filter(owner__username=username).order_by('-createdAt')
This is my IsFromSameLocation permission:
class IsFromSameLocation(permissions.BasePermission):
"""
Permission.
Allow permissions to authenticated users from the same
location as the user.
"""
message = 'Not from the same location.'
def has_permission(self, request, view):
username = view.kwargs.get('username', None)
try:
userProfile = User.objects.get(username=username)
except:
return False
return request.user.userextended.location == userProfile.userextended.location
With that said, in my get_queryset() method, I do user = User.objects.get(username=username) but if the user does not exist, I want to raise a 404 error. I know that get_queryset() is supposed to return a queryset, so I'm guessing I shouldn't raise a 404 in that method. So where exactly should I do the check to see if the user exists or not? Note that in my permission, I do do a try and except to see if the user exists, but permissions should only return True or False from my understanding (not raise 404 errors).
You actually can raise an exception from a permission and it will be correctly handled by Django. For example you can do it with get_object_or_404() shortcut function:
def has_permission(self, request, view):
username = view.kwargs.get('username', None)
userProfile = get_object_or_404(User, username=username)
return request.user.userextended.location == userProfile.userextended.location
In fact, while the code that throws an exception is executed in a view, it will be handled by Django, so it should not matter where you are raising it from -- from view, serializer, permission, model etc. methods.
The easiest way is to raise a Http404 exception:
In your try/except block, raise the 404 in the exception, but its probably worth limiting the exception to just DoesNotExist errors:
try:
userProfile = User.objects.get(username=username)
except User.DoesNotExist:
from django.http import Http404
raise Http404("User does not exist")
When user authenticates in Django, how do I check that from tastypie?
Once user logs on, the view includes some JS that pulls data from API, which is backed by tastypie.
I have basic authentication/djangoauthorisation set up on my resources, so the browser pops up http auth window. Is there any way to avoid this?
My idea so far is to extend BasicAuthentication so that it first checks session data and when it doesn't find it, it falls back to http auth? AFAIK AJAX calls include session cookies, so this in theory should work? Has anybody done something similar?
I have this solution so far:
class MyBasicAuthentication(BasicAuthentication):
def __init__(self, *args, **kwargs):
super(MyBasicAuthentication, self).__init__(*args, **kwargs)
def is_authenticated(self, request, **kwargs):
from django.contrib.sessions.models import Session
if 'sessionid' in request.COOKIES:
s = Session.objects.get(pk=request.COOKIES['sessionid'])
if '_auth_user_id' in s.get_decoded():
u = User.objects.get(id=s.get_decoded()['_auth_user_id'])
request.user = u
return True
return super(MyBasicAuthentication, self).is_authenticated(request, **kwargs)
which seems to do what I want. If user is logged on, then session contains _auth_user_id, if not, the key is missing.
Anyone can think of any problems this approach may cause?
You may want to check out this ticket on tastypie's GitHub:
https://github.com/toastdriven/django-tastypie/issues/197
The author suggests a very clean approach to authenticate the call with both the session and the API key methods.
There goes the snippet:
class ApiKeyPlusWebAuthentication(ApiKeyAuthentication):
def is_authenticated(self, request, **kwargs):
if request.user.is_authenticated():
return True
return super(ApiKeyPlusWebAuthentication, self).is_authenticated(request, **kwargs)
def get_identifier(self, request):
if request.user.is_authenticated():
return request.user.username
else:
return super(ApiKeyPlusWebAuthentication, self).get_identifier(request)
Once the user is logged in through your API, you have a Django user session. If you want to check if the user is still logged in (on page refresh for example). You can do:
from tastypie.resources import Resource
class LoggedInResource(Resource):
class Meta:
pass
def get_list(self, request, **kwargs):
from django.http import HttpResponse
if request.user.is_authenticated():
return HttpResponse(status=200)
else:
return HttpResponse(status=401)
Client check:
$.ajax({
type: "GET",
url: '/api/loggedin/',
success: function(data) {
// logged in
},
error: function() {
// not logged in
}
});
Pulegium
Why not just as simple as the following:
class CommAuthentication(BasicAuthentication):
def __init__(self, *args, **kwargs):
super(CommAuthentication, self).__init__(*args, **kwargs)
def is_authenticated(self, request, **kwargs):
return request.user.is_authenticated()
I just start to learn tastypie. the above code seemed works for me. Any advantage of your solution ?
Hey there, im a little bit confused about handling invalid user authentication request, at login controller. So, i already have modified login view, but cant figure out where to put the exception handling block. It should work like this: you login - if its incorrect you will see warning message at /login .
Any ideas ?
What strategy have you chosen ? In my custom Strategy, I call the class method 'authenticate' on my User class:
class User
def self.authenticate(login, password)
u = User.first(:conditions => ['email = ?', login]) # find a user with this login
if u && u.authenticated?
return u
else
nil
end
end
end
Also, you might want to look at the source code of merb-auth-more/mixins/salted_user which is a module that is automatically mixed into your User class.
you would put your exception handling action in the exceptions controller
# handle NotAuthorized exceptions (403)
def not_authorized
render :format => :html
end
and to customise the view you would create a template in app/views/exceptions/not_authorized.html.haml