Can not send POST request to Flask app using axios - flask

I'm simply trying to send a json post request using axios to Flask. But I get 'OPTIONS' in the server console which I understood is the preflight request. And I found if I use x-www-form-urlencoded instead of application/json in the headers of axios, the browser doesn't do a preflight request, so I was getting a POST request finally. But the block of POST request (as you can see in the code below) still doesn't get hit. I keep getting a CORS issue even though I've set the Access control allow origins in the server. What could be the problem here?
//FLASK SERVER
#bp.route("/", methods=["GET", "POST"])
def recipes():
if request.method == "GET":
# show all the recipes
recipes = [
{'name': 'BURGER', 'ingredients': ['this', 'that', 'blah']},
{'name': 'CHICKEN'}
]
return jsonify(recipes)
elif request.method == "POST":
# save a recipe
print('SEE HEREEE'+ str(request.data))
print(request.is_json)
content = request.get_json()
print(content)
return jsonify(content), 201, {'Access-Control-Allow-Origin': '*', 'Access-Control-Request-Method': "*", 'Access-Control-Allow-Headers': "*"}
//FRONTEND
try{
let response = await axios({
method: "POST",
url: "http://localhost:5000/recipes/",
headers: {
"Content-Type": "*"
},
data: {"hello": "HI"}
});
console.log("RESPONSE HERE", response)
}catch(err){
throw new Error("ERROR", err)
}
//Browser Console

If there is any error in Python code it shows similar error in front end side. From your screenshot, I see that there is an error in LoginForm. I think that is why the front end is not working as expected.
To handle CORS error, I use flask_cors Flask extension. Details of the package can be found in this Pypi package repository.
I have simplified the code to test if the CORS error occurs when there is no error in back end. I can add a new recipe using POST request from Axios.
Backend:
from flask import Flask, render_template, jsonify, request
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
#app.route("/recipes", methods = ['GET', 'POST'])
def recipes():
# recipes
recipes = [
{'name': 'BURGER', 'ingredients': ['this', 'that', 'blah']},
{'name': 'HOTDOG', 'ingredients': ['Chicken', 'Bread']}
]
if request.method == "GET":
return jsonify(recipes)
elif request.method == "POST":
content = request.get_json()
recipes.append(content)
return jsonify(recipes)
Frontend:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Frontend Application</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="result">
</div>
<script type="text/javascript">
axios.post('http://127.0.0.1:5000/recipes', {
name: 'Sandwich',
ingredients: ['Vegetables', 'Sliced cheese', 'Meat']
})
.then(function (response) {
var result = document.getElementById("result");
const data = response.data;
for(var i=0; i<data.length; i++){
const item = data[i];
result.innerHTML+=item.name+": "+item.ingredients+"<br>";
}
})
.catch(function (error) {
console.log(error);
});
</script>
</body>
</html>
Output:

Related

CORS policy blocks XMLHttpRequest

With Ionic Angular running in on my localhost I made this call to my Django backend (running on different localhost):
test() {
return this.httpClient.get(endpoint + '/test', {
headers: { mode: 'no-cors' },
});
}
And on the backend side I have following code to respond:
#csrf_exempt
def test(request):
response = json.dumps({'success': True})
return HttpResponse(response, content_type='application/json', headers={'Access-Control-Allow-Origin': '*'})
I have also this in my settings.py file:
INSTALLED_APPS = [
...
'corsheaders',
]
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
]
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True
Still, I get this error message in my console:
Access to XMLHttpRequest at 'http://127.0.0.1:8000/test' from origin 'http://localhost:8100' has been blocked by CORS policy: Request header field mode is not allowed by Access-Control-Allow-Headers in preflight response.
What am I doing wrong?
You need to just add one more setting
CORS_ALLOW_ALL_HEADERS=True
Other than the above you do not need to set a header on each response. Just simply respond back with payload as
#csrf_exempt
def test(request):
response = json.dumps({'success': True})
return HttpResponse(response, content_type='application/json', headers={'Access-Control-Allow-Origin': '*'})

Django CSRF and axios post 403 Forbidden

I use Django with graphene for back-end and Nuxt for front-end. The problem appears when I try post requests from nuxt to django. In postman everything works great, in nuxt I receive a 403 error.
Django
# url.py
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', GraphQLView.as_view(graphiql=settings.DEBUG,
schema=schema)),
]
# settings.py
CORS_ORIGIN_WHITELIST = 'http://localhost:3000'
CORS_ALLOW_CREDENTIALS = True
CSRF_USE_SESIONS = False
CSRF_COOKIE_HTTPONLY = False
CSRF_COOKIE_SAMESITE = None
NuxtJs
# nuxt.config.js
axios: {
baseURL: 'http://127.0.0.1:8000/',
debug: false,
progress: true,
credentials: true
},
# plugins/axios.js
await $axios.onRequest((config) => {
config.headers.common['Content-Type'] = 'application/json'
config.xsrfCookieName = 'csrftoken'
config.xsrfHeaderName = 'X-CSRFToken'
const csrfCookie = app.$cookies.get('csrftoken')
config.headers.common['X-CSRFToken'] = csrfCookie
console.log(config)
# store/contact.js
import { AddMessage } from '../queries/contact.js'
export const actions = {
async send() {
const message = await this.$axios({
url: 'api/',
method: 'POST',
data: AddMessage
})
}
}
# queries/contact.js
export const AddMessage = {
query: `
mutation AddContact($input: AddMessageInput!){
addMessage(input: $input){
message{
name
email
body
terms
}
}
}
`,
variables: `
{
"input":{
"name": "test",
"email": "test#test.com",
"body": "test",
"terms": true,
}
}
`,
operationName: 'AddMessage'
}
Somethig that
Here are request headers from axios post. Something strange for me is the cookie with a wrong value. The good value of token is present in X-CSRFToken header.
Here is the log from axios post request. Another strange thing for me is the undefined headers: Content-Type and X-CSRFToken
Thank you!
I resolved this problem and I want to share the solution here.
The problem with wrong cookie value was generated by the front end app that managed (I don't remember how) to get csrf cookie from the back end app. In X-CSRFToken header was token received from response's Set-cookie header and in Cookie header was the cookie from back end app.
After I changed localhost with 127.0.0.1 and added
config.xsrfCookieName = 'csrftoken' in axios plugin
I was able to separate the apps, save and use cookies independent.
The second problem, with undefined headers was generated by axios. These 2 line of code resolved the problem. These were added also in axios onRequest method.
config.xsrfHeaderName = 'X-CSRFToken'
config.headers['Content-Type'] = 'application/json'

Axios put request not working properly with Django Rest Framework

From axios I have to make a put request to the DRF. In DRF I'm using APIView class-based view. Before I was getting 403 forbidden error when I was making put request. Because it was not sending csrftoken in the request. I googled it and went through the CSRF with Django, React+Redux using Axios stack overflow question and somehow I was able to fix 403 forbidden issue.
Going through the above StackOverflow question I changed a few lines of codes and they are.
In my axios file
axios.defaults.xsrfHeaderName = "X-CSRFToken";
axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.withCredentials = true;
In my project's settings. py file
ALLOWED_HOSTS = ['*']
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
But the wiered part is here when I pass any data to thorough put request from axios, it actually passing the flow to the APIView class (It's my assumption) from there I get a wired response. I could see that it sends the react's index.html as the data in the response.
My views.py code
class TestView(APIView):
def put(self, request):
print('inside put method')
print(request.data)
return Response('Test data passing in return')
My Axios code
import axios from "axios";
axios.defaults.xsrfHeaderName = "X-CSRFToken";
axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.withCredentials = true;
return axios({
method: "put",
url: API_URL,
data: alterRecord
})
.then(res => {
console.log("inside then");
console.log(res);
})
.catch(e => {
console.log("Inside catch");
console.log(e.message);
});
In my APIView class for testing purpose, I've added print statements and it doesn't print those lines in the command line. When I saw the requests in the command line, I saw that OPTIONS method also being called I'm not sure why.
[09/Oct/2019 18:02:09] "OPTIONS /api/url/ HTTP/1.1" 200 0
[09/Oct/2019 18:02:09] "PUT /api/url/ HTTP/1.1" 200 2102
In the axios response data i can see that it's passing react's index.html data like this
data: "<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>NoA</title><link href="/static/css/2.39680177.chunk.css" rel="stylesheet"><link href="/static/css/main.87078788.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(l){function e(e){for(var r,t,n=e[0],o=e[1],u=e[2],f=0,i=[];f<n.length;f++)t=n[f],p[t]&&i.push(p[t][0]),p[t]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(l[r]=o[r]);for(s&&s(e);i.length;)i.shift()();return c.push.apply(c,u||[]),a()}function a(){for(var e,r=0;r<c.length;r++){for(var t=c[r],n=!0,o=1;o<t.length;o++){var u=t[o];0!==p[u]&&(n=!1)}n&&(c.splice(r--,1),e=f(f.s=t[0]))}return e}var t={},p={1:0},c=[];function f(e){if(t[e])return t[e].exports;var r=t[e]={i:e,l:!1,exports:{}};return l[e].call(r.exports,r,r.exports,f),r.l=!0,r.exports}f.m=l,f.c=t,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(r,e){if(1&e&&(r=f(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var n in r)f.d(t,n,function(e){return r[e]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var r=window.webpackJsonp=window.webpackJsonp||[],n=r.push.bind(r);r.push=e,r=r.slice();for(var o=0;o<r.length;o++)e(r[o]);var s=n;a()}([])</script><script src="/static/js/2.46fe2ccd.chunk.js"></script><script src="/static/js/main.c9f4f998.chunk.js"></script></body></html>"
Here I'm not sure why print statements are not getting printed, why OPTION HTTP method is getting called here and also why am I getting react's index.html as a response instead of Response('Test data passing in return').
If I do the same request from postman it actually sends back the response correctly. But with axios it does not. I'm sure I've to do something with axios. Please, can anyone assist me with this?

i am learning django websocket everything is working fine except for my JS function in HTML file

I am working on django websocket and creating an Echo app but i don't know why i am getting this error
Here is my html code
{% load staticfiles %}
<html>
<head>
<title>Notifier</title>
<script src="{% static '/channels/js/websocketbridge.js' %}" type="text/javascript"></script>
</head>
<body>
<h1>Notifier</h1>
<script>
document.addEventListener('DOMContentLoaded', function() {
const webSocketBridge = new channels.WebSocketBridge();
webSocketBridge.connect('/ws/');
webSocketBridge.listen(function(action, stream) {
console.log("RESPONSE:", action, stream);
})
document.ws = webSocketBridge; /* for debugging */
})
</script>
</body>
</html>
This is my views.py
from django.views.generic import TemplateView
class HomeView(TemplateView):
template_name = "home.html"
This is my routing.py
from channels.routing import ProtocolTypeRouter, URLRouter
from django.urls import path
from notifier.consumers import EchoConsumer
application = ProtocolTypeRouter({
"websocket": URLRouter([
path("ws/", EchoConsumer),
])
})
Tihs is my counsumers.py
from channels.consumer import AsyncConsumer
class EchoConsumer(AsyncConsumer):
async def websocket_connect(self, event):
await self.send({
"type": "websocket.accept"
})
async def websocket_receive(self, event):
# Echo the same received payload
await self.send({
"type": "websocket.send",
"text": event["text"]
})
Guide me with my mistake where and what i am doing wrong in this whole system i do not find any solution on internet i would expect this code to run properly and do an Echo on my browser console.

Django 403 forbidden when sending Post-requests from Angular only when user is logged on

I've created a back-end Django application and am currently working on hooking up an Angular front-end that requests data from API's set up using Django rest framework and have run into the problem that my logged in users (in the back-end, them being logged in on the front-end doesn't matter) get 403 on all post-requests to the API. Which I figure is because of the CSRF protection in Django.
I have look at a thread that tackled this exact problem for this and have attempted to implement the solution from this thread with no luck.
Logged out users can send post-requests to register or log in just fine. But when a logged in user tries to it gets a 403. Sending the same data while browsing the DRF API is successful, which is why I think it's related to CSRF. To be a little more clear, if I'm logged in as a user on the front-end and try to log-in or register a new user (those parts aren't blocked off in development) I get a 403 response. If I'm logged in on the browsable API and send the exact same post-content it works with successfully attempting to log me in again, or register a new user.
Can it be because of the custom header I'm adding that may be replacing the CSRF header? In that case, how can I remake it since that header is needed or else I get a 415 unsupported media type.
Here is the Angular service that provides the function that sends a login request to the server:
import { Injectable } from '#angular/core';
import { Observable, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators'
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Userlogon } from '../_models/Userlogon';
import { User } from '../_models/User';
const HttpOptions = {
headers: new HttpHeaders({ "Content-type": "application/json" })
};
#Injectable({
providedIn: 'root'
})
export class AuthService {
loginobject: any;
private usersUrl= '/api/v1/accounts/';
private logonUrl= '/api/v1/auth/login/';
private logoutUrl= '/api/v1/auth/logout/';
constructor(
private http: HttpClient
) { }
login(username: string, password: string) {
this.loginobject=JSON.stringify({"username": username, "password": password});
return this.http.post<any>(this.logonUrl, this.loginobject, HttpOptions)
.pipe(map(user => {
if (user){
console.log("If statement satisfied");
localStorage.setItem('currentUser', JSON.stringify(user));
}
return user;
}));
}
logout(){
localStorage.removeItem('currentUser');
return this.http.get<any>(this.logoutUrl).subscribe(response => console.log(response));
}
}
Here is the app module where I've implemented the provider options:
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { NgModule } from '#angular/core';
import { HttpClientModule } from '#angular/common/http';
import { HttpModule, XSRFStrategy, CookieXSRFStrategy } from '#angular/http'
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { RegisterComponent } from './register/register.component';
import { LoginComponent } from './login/login.component';
import { AlertComponent } from './_directives/alert.component';
import { ProfileComponent } from './profile/profile.component';
import { AuthGuardService } from './_guards/auth-guard.service';
import { AlertService } from './_services/alert.service';
import { AuthService } from './_services/auth.service';
import { UserService } from './_services/User.service';
#NgModule({
declarations: [
AppComponent,
RegisterComponent,
LoginComponent,
AlertComponent,
ProfileComponent,
],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
AppRoutingModule,
HttpClientModule,
HttpModule
],
providers: [
{
provide: XSRFStrategy,
useValue: new CookieXSRFStrategy('csrftoken', 'X-CSRFToken')
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
Here is the template that Django in processes:
{% load static %}
{% csrf_token %}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AngularWebapp</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<app-root></app-root>
{% block javascript %}
<script type="text/javascript" src="{% static 'runtime.js' %}"></script><script type="text/javascript" src="{% static 'polyfills.js' %}"></script><script type="text/javascript" src="{% static 'styles.js' %}"></script><script type="text/javascript" src="{% static 'vendor.js' %}"></script><script type="text/javascript" src="{% static 'main.js' %}"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
{% endblock %}
</body>
</html>
And lastly the Django view-code:
from django.shortcuts import render
from django.contrib.auth import authenticate, login, logout
from rest_framework import permissions, viewsets, status
from rest_framework.views import APIView
from rest_framework.response import Response
from authentication.models import Account
from authentication.permissions import IsAccountOwner
from authentication.serializers import AccountSerializer, LoginSerializer
from getorgname import scrapeorg, idgenerator
import json
# Create your views here.
class AccountViewSet(viewsets.ModelViewSet):
lookup_field='username'
queryset=Account.objects.all()
serializer_class= AccountSerializer
def get_permissions(self):
if self.request.method in permissions.SAFE_METHODS:
return (permissions.AllowAny(),)
if self.request.method == 'POST':
return (permissions.AllowAny(),)
return (permissions.IsAuthenticated(), IsAccountOwner(),)
def create(self, request):
serializer=self.serializer_class(data=request.data)
if serializer.is_valid():
newuser=serializer.validated_data
Account.objects.create_user(
username=newuser.get('username'),
email=newuser.get('email'),
org_name=scrapeorg(newuser.get('org_number')),
org_number=newuser.get('org_number'),
cid=idgenerator(),
utype=newuser.get('utype'),
password=newuser.get('password'),
)
#Account.objects.create_user(**serializer.validated_data)
return Response(serializer.validated_data, status=status.HTTP_201_CREATED)
return Response({
'status': 'Bad request',
'message': 'Account could not be created with received data',
}, status=status.HTTP_400_BAD_REQUEST)
class LoginView(APIView):
def post(self, request):
#data=json.loads(request.body)
serializer=LoginSerializer(data=request.data)
if serializer.is_valid():
data=serializer.validated_data
username=data.get('username')
password=data.get('password')
account=authenticate(username=username, password=password)
if account != None:
login(request, account)
serialized = AccountSerializer(account)
return Response(serialized.data)
else:
return Response({
'status': 'Unauthorized',
'message': 'Username %s and password invalid' % username
}, status=status.HTTP_401_UNAUTHORIZED)
return Response({
'status': 'Bad request',
'message': 'Invalid data for a login request',
}, status=status.HTTP_400_BAD_REQUEST)
class LogoutView(APIView):
def get_permissions(self):
return (permissions.IsAuthenticated(), IsAccountOwner(),)
def get(self, request):
logout(request)
return Response({
'status': 'Success',
'message': 'Successfully processed logout request',
})