Django receiving json post request from external source - python

I have written a view function that processes a post request containing json data from a source outside of django (labview). I'm just testing it to begin with so it looks like this
def post_entry(request):
'''Process incoming json string
'''
if request.method == 'POST':
post_data = request.body
# Return a response
return HttpResponse('data received OK')
I've written a test to test this and it passes fine:
def test_post_entry_view_good_post_data(self):
'''post_entry view should return a 200 status if valid
'''
data = {'DHTP Data': ['10', '50.296', '50.94', '50.418', '50.425', '50.431', '50.94'],
'Test String': 'My Test String'}
request_url = reverse('post_entry')
response = self.client.post(request_url, content_type='application/json',
data=dumps(data))
# Should return a 200 response indicating ok
self.assertEqual(response.status_code, 200)
But when labview posts the data post_entry returns a 403 forbidden error. I guess this is due to no csrf token being present, but why does the test pass in this case?

The test client works around the CSRF functionality. See https://docs.djangoproject.com/en/1.9/ref/csrf/#testing

If you are going to have a view that accepts post data from a source external to your app you need to make your view exempt from CSRF protection by using csrf_exempt:
#csrf_exempt
def post_entry(request):
'''Process incoming json string
'''
If you are going to do this, you should use some other method of validating the request

If your view is supposed to accept POST from external sources it is upon you to validate the request as every POST request is required to have a CSRF token (Refer: CSRF). Hence, for your purpose, you'll have to exempt the view from CSRF validation using #csrf_exempt decorator and write your own validation for the request using something like Token Authentication

Use this line to get the decorator needed to bypass CSRF protection:
from django.views.decorators.csrf import csrf_exempt
then put the #csrf_exempt decorator on the line before your function.

Related

How do I return the request body in a POST request?

I'm using fastapi and python. Using a POST method to successfully return data. However, I need to return the request body of my post method to use for some business logic ideally before sending off the query to my database.
How do I go about doing this?
Currently trying return Request.json but it's returning a hexedecmial value.
As mentioned here FastAPI: how to read body as any valid json?, you simply use the Request object:
from fastapi import Request, FastAPI
#app.post("/dummypath")
async def get_body(request: Request):
return await request.json()
It return a python dictionary, if the request passed a json formatted body, otherwise check what you request is sending.

Flask return JWT token when redirecting

I have been following this Flask pyjwt guide, however my web app is somewhat similar to Miguel's microblog example that uses render_template() and redirect(url_for(...)) for navigation.
I have implemented an encoding and decoding service in my application, however I do not know how to properly return the encoded JWT token to the user using redirect()
My code is as follows:
#app.route('/', methods=['GET', 'POST'])
def login():
login_form = LoginForm()
username = login_form.username.data
password = login_form.password.data
if is_user_valid(username, password):
return redirect(url_for('home'), auth_service.encode_token(username))
render_template('login.html', form=login_form)
My problem is placing the auth token inside the redirect method causes a page to appear saying "Redirecting... you should be redirected, if not click here", which I do not want. I do not particularly wish to change my redirect methods to something similar to make_response(jsonify(...)) as I would then need to handle these responses in the front end when this is a simple login page.
How should I be returning the auth token to the client correctly?
Typically you attach it to response headers which is what your redirect method returns.
response = redirect(url_for('home'))
response.headers['X-JWT-TOKEN'] = auth_service.encode_token(username)
return response
However, I'm not sure if this is gonna be very useful in your setup when using render_template, because you can not easily access these headers on the frontend.
You have two alternatives here:
Make your login endpoint an API. This way you can return the token for the client-side code to handle and store it somehow.
Drop the JWT and stick to using sessions. I know that this is not what you expected, but outside of building APIs JWT-based auth is not very helpful.

Sending POST request with JSON data in DJANGO and response from view also JSON data but its giving 403 FORBIDDEN error

I am trying to send a POST request to Django with JSON data in it and the view is returning response with JSON data. But when I send a request to it, it returns with 403 Forbidden error. I am using RESTClient to send/test POST requests.
I have read all about CSRF in documentation but its not very helpful. I am fairly new to Django and the other questions posted here are not helping me a lot.
The code in my view is:
from django.shortcuts import render
from django.http import HttpResponse;
import json;
def index(request):
if request.is_ajax():
if request.method == 'POST':
print 'Raw Data: "%s"' % request.body;
reply = json.loads(request.body);
return HttpResponse(reply);
else:
return HttpResponse("OK");
else:
return HttpResponse("OK");
In addition to #ArpitGoyal's answer you can also decorate your view with csrf_exempt:
This decorator marks a view as being exempt from the protection ensured by the middleware.
A few tips in case you do need CSRF protection:
Check CSRF token cookie name.
See CSRF_COOKIE_NAME for more information.
Add ensure_csrf_cookie decorator to your view.
According to the docs:
Warning
If your view is not rendering a template containing the csrf_token template tag, Django might not set the CSRF token cookie. This is common in cases where forms are dynamically added to the page. To address this case, Django provides a view decorator which forces setting of the cookie: ensure_csrf_cookie().
Assuming that CSRF token cookie name is csrftoken, try to send X-CSRFToken header.
$.ajax({
// Your options here.
headers: {'X-CSRFToken': getCookie('csrftoken')}
});
You should authenticate your client before making the request. From your call you are providing a ajax POST request hit.
Provide a header in your RESTClient: X-CSRFToken.
For more details view this

Django - test client receives 403 because of csrf

I'm using Django 1.6 and python 3.3.
I'm trying to test POST form with django test client, and it receives 403 after sending request. If I add #csrf_exempt at my view method, everything works perfect.
But the Django documentation says that it should work with enabled csrf protection fine:
For this reason, Django’s HTTP client for tests has been modified to set a flag on requests which relaxes the middleware and the csrf_protect decorator so that they no longer rejects requests.
Here is my test code:
def testSimple(self):
c = Client('Chrome 1.0')
from partners.views import cashier
response = c.post(reverse(cashier.simple), {'x': 123})
self.assertContains(response,'html')
And here is a view:
def simple(request):
return render(request, 'partners/cashier/index.html')
And when I run this test I see:
AssertionError: 403 != 200
So, can you please tell me what I'm doing wrong?
Client() has the following __init__:
def __init__(self, enforce_csrf_checks=False, **defaults):
You're setting enforce_csrf_checks to True b/c 'Chrome 1.0' evaluates to truthy!
If you want to set the user agent:
c = Client(HTTP_USER_AGENT='Mozilla/5.0')

Using Requests python library to connect Django app failed on authentication

Maybe a stupid question here:
Is Requests(A python HTTP lib) support Django 1.4 ?
I use Requests follow the Official Quick Start like below:
requests.get('http://127.0.0.1:8000/getAllTracks', auth=('myUser', 'myPass'))
but i never get authentication right.(Of course i've checked the url, username, password again and again.)
The above url 'http://127.0.0.1:8000/getAllTracks' matches an url pattern of the url.py of a Django project, and that url pattern's callback is the 'getAllTracks' view of a Django app.
If i comment out the authentication code of the 'getAllTracks' view, then the above code works OK, but if i add those authentication code back for the view, then the above code never get authenticated right.
The authentication code of the view is actually very simple, exactly like below (The second line):
def getAllTracks(request):
if request.user.is_authenticated():
tracks = Tracks.objects.all()
if tracks:
# Do sth. here
Which means if i delete the above second line(with some indents adjustments of course), then the requests.get() operation do the right thing for me, but if not(keep the second line), then it never get it right.
Any help would be appreciated.
In Django authentication works in following way:
There is a SessionMiddleware and AuthenticationMiddleware. The process_request() of both these classes is called before any view is called.
SessionMiddleware uses cookies at a lower level. It checks for a cookie named sessionid and try to associate this cookie with a user.
AuthenticationMiddleware checks if this cookie is associated with an user then sets request.user as that corresponding user. If the cookie sessionid is not found or can't be associated with any user, then request.user is set to an instance of AnonymousUser().
Since Http is a stateless protocol, django maintains session for a particular user using these two middlewares and using cookies at a lower level.
Coming to the code, so that requests can work with django.
You must first call the view where you authenticate and login the user. The response from this view will contain sessionid in cookies.
You should use this cookie and send it in the next request so that django can authenticate this particular user and so that your request.user.is_authenticated() passes.
from django.contrib.auth import authenticate, login
def login_user(request):
user = authenticate(username=request.POST.get('username'), password=request.POST.get('password'))
if user:
login(request, user)
return HttpResponse("Logged In")
return HttpResponse("Not Logged In")
def getAllTracks(request):
if request.user.is_authenticated():
return HttpResponse("Authenticated user")
return HttpResponse("Non Authenticated user")
Making the requests:
import requests
resp = requests.post('http://127.0.0.1:8000/login/', {'username': 'akshar', 'password': 'abc'})
print resp.status_code
200 #output
print resp.content
'Logged In' #output
cookies = dict(sessionid=resp.cookies.get('sessionid'))
print cookies
{'sessionid': '1fe38ea7b22b4d4f8d1b391e1ea816c0'} #output
response_two = requests.get('http://127.0.0.1:8000/getAllTracks/', cookies=cookies)
Notice that we pass cookies using cookies keyword argument
print response_two.status_code
200 #output
print response_two.content
'Authenticated user' #output
So, our request.user.is_authenticated() worked properly.
response_three = requests.get('http://127.0.0.1:8000/hogwarts/getAllTracks/')
Notice we do not pass the cookies here.
print response_three.content
'Non Authenticated user' #output
I guess, auth keyword for Requests enables HTTP Basic authentication which is not what is used in Django. You should make a POST request to login url of your project with username and password provided in POST data, after that your Requests instance will receive a session cookie with saved authentication data and will be able to do successful requests to auth-protected views.
Might be easier for you to just set a cookie on initial authentication, pass that back to the client, and then for future requests expect the client to send back that token in the headers, like so:
r = requests.post('http://127.0.0.1:8000', auth=(UN, PW))
self.token = r.cookies['token']
self.headers = {'token': token}
and then in further calls you could, assuming you're in the same class, just do:
r = requests.post('http://127.0.0.1:8000/getAllTracks', headers=self.headers)

Categories

Resources