I'm trying to make a post request from a react frontend to a django backend to log a user in, and redirect to a new page. The issue I'm having is that even though the request reaches the server and I can get the data when it comes time for django to redirect, the redirect does not happen and their is an output in the console that says "Broken pipe from ('127.0.0.1', 64989)". I've done some research online about this issue, but I still can't figure out how to fix it. However, everything works fine when I use a an html form element with an action and method type. Below I have shared my code.
React Frontend
handleSubmit = () => {
let csrfToken = Cookies.get('csrftoken')
let endpoint = this.state.isLoggingIn ? LOGIN_ENDPOINT : REGISTER_ENDPOINT;
axios({
url: endpoint,
method: "POST",
data: {
username: this.state.username,
password: this.state.password,
displayName: this.state.displayName,
},
headers: {"X-CSRFToken": csrfToken},
responseType: "json",
}).then(function (response) {
console.log(response);
}).catch(function (error) {
console.log(error);
});
}
Django Backend
def login_view(request):
if request.method == 'POST':
#username = request.POST.get('username') <= I use this and below, to get data sent via a form with an action and method set.
#password = request.POST.get('password')
body_unicode = request.body.decode('utf-8')
data = simplejson.loads(body_unicode)
username = data['username']
password = data['password']
user = authenticate(username=username, password=password)
print user
if user is not None and user.is_active:
login(request, user)
return redirect('chat_app:chat')
else:
return JsonResponse({'message': 'Check you username or password'})
else:
return render(request, 'frontend/chat_app/home.html')
Following works but is not what I want
With this method I can get the data from the input fields (not shown here)
authenticate the user and redirect them properly. However, I do not want to
use this method because I want to pass back any error messages to the submitFunction() that had been called, or process any other data, in the same page that had made the call.
<form method="POST" action={ENDPOINT}>
<input
type="hidden"
name="csrfmiddlewaretoken"
value={csrftoken}
/>
....
Related
I am working on this CS50W project.
When using the fetch API to send POST requests to the server, everything worked fine.
After I changed the method to PUT, or any other unsafe methods, things stopped working.
Javascript
let like_form = document.querySelector('#like-form');
let data = new FormData(like_form);
fetch(`post/${post_id}/like`, {
method: 'POST',
body: data,
credentials: "same-origin"
})
views.py
#login_required
def like_post(request, post_id):
if request.method == 'POST':
post = get_post(post_id)
if post:
if request.user in post.liked_by.all():
post.liked_by.remove(request.user)
status = False
else:
post.liked_by.add(request.user)
status = True
return JsonResponse({
'message': 'Success.',
'status': status
}, status=200)
index.html
<form id='like-form'>
{% csrf_token %}
</form>
Output using POST
{message: 'Success.', status: false}
Output using PUT
PUT http://127.0.0.1:8000/post/17/like 403 (Forbidden)
Forbidden (CSRF token missing.): /post/17/like
The only thing I changed was the method in fetch and views.py
Any help will be appreciated.
After going into the source code, I found out that for PUT, the csrf_token is read from the headers of the request instead of the body. Therefore adding
headers: {
'x-csrftoken': CSRF_TOKEN_ELEMENT.value
}
solved the problem
I am struggling with setting jwt token in httponly cookie. I tried many solution but not working. I am working with localhost "127.0.0.1" but when I try to login the cookies sent by server not display in my frontend working at "127.0.0.1:5501" but if I try with Browsable api working at "127.0.0.1:8000" it works fine and I can check my cookies easily.
I noticed a weird thing too. If I login via my frontend "127.0.0.1:5501", cookies not set but if I try with browsable api working at "127.0.0.1:8000" and then switch to my "127.0.0.1:5501" tab I can see that cookies their too. This a very Weird thing and I don't know the reason behind this.
Please help me to resolve this issue.
Views.py
class LoginView(APIView):
def post(self,request,format=None):
data = request.data
response = Response()
username = data.get('username', None)
password = data.get('password', None)
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
data = get_tokens_for_user(user)
response.set_cookie(
key = settings.SIMPLE_JWT['AUTH_COOKIE'],
value = data["access"],
expires = settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'],
secure = settings.SIMPLE_JWT['AUTH_COOKIE_SECURE'],
httponly = settings.SIMPLE_JWT['AUTH_COOKIE_HTTP_ONLY'],
samesite = settings.SIMPLE_JWT['AUTH_COOKIE_SAMESITE']
)
csrf.get_token(request)
response.data = {"Success" : "Login successfully","data":data}
return response
else:
return Response({"No active" : "This account is not active!!"},status=status.HTTP_404_NOT_FOUND)
else:
return Response({"Invalid" : "Invalid username or password!!"},status=status.HTTP_404_NOT_FOUND)
Fetch Api request
async function login(email,password)
{
let response = await fetch('http://127.0.0.1:8000/api/account/login/',{
method: 'POST',
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
},
withCredentials: true,
body: JSON.stringify({
'username': email,
'password': password
})
})
return response;
}
Settings.py file
ALLOWED_HOSTS = ['127.0.0.1']
CORS_ALLOW_HEADERS = default_headers + (
'Access-Control-Allow-Origin',
)
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOWED_ORIGINS = [
"http://127.0.0.1:5501",
]
# ////////////////custom settings/////////////source : stackoverflow/////////////////////
'AUTH_COOKIE': 'access_token', # Cookie name. Enables cookies if value is set.
'AUTH_COOKIE_DOMAIN': None, # A string like "example.com", or None for standard domain cookie.
'AUTH_COOKIE_SECURE': False, # Whether the auth cookies should be secure (https:// only).
'AUTH_COOKIE_HTTP_ONLY' : True, # Http only cookie flag.It's not fetch by javascript.
'AUTH_COOKIE_PATH': '/', # The path of the auth cookie.
'AUTH_COOKIE_SAMESITE': 'Lax', # Whether to set the flag restricting cookie leaks on cross-site requests.
# This can be 'Lax', 'Strict', or None to disable the flag.
Postman demo
Browsable api demo
Frontend demo
If you are also struggling with this issue. Just make sure that you have above setting and follow this simple update.
let response = await fetch('http://127.0.0.1:8000/api/account/login/',{
method: 'POST',
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
},
credentials: 'include',
body: JSON.stringify({
'username': email,
'password': password
})
})
It should be credentials only.
I have a user registration form and I would like the user to pay in order to register for my app.
I have the frontend paypal set up for the payment as well as the user registration with a submit button but I do not know how to integrate the two.
<div id="paypal-button-container"></div>
<script src="https://www.paypal.com/sdk/js?client-id=sb¤cy=USD"></script>
<script>
// Render the PayPal button into #paypal-button-container
paypal.Buttons({
// Set up the transaction
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: '00.01'
}
}]
});
},
// Finalize the transaction
onApprove: function(data, actions) {
return actions.order.capture().then(function(details) {
// Show a success message to the buyer
alert('Transaction completed by ' + details.payer.name.given_name + '!');
});
}
}).render('#paypal-button-container');
</script>
<button class="w3-button w3-blue w3-padding-large" type="submit">
Buy Now
</button>
</form>
I would like the submit button to be used in the 'onapprove' part of the script but I am not sure how. Alternatively I was thinking of calling my 'buy' function from the views
def buy(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
data = form.cleaned_data
email = f"{data['email']}"
username = f"{data['username']}"
form.instance.username = username
form.save()
return redirect('login')
else:
form = UserRegisterForm()
return render(request, 'users/buy.html', {'form': form})
The other thing is that the system would have to check that the form inputs are unique and valid before payment. Would it just be best to have the redirect the user to the registration page following a successful payment?
forms.py
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
username = forms.CharField(max_length=20)
class Meta:
model = User
fields = ['email', 'username', 'password1', 'password2']
You can use onClick to check the values are valid before proceeding with payment: https://developer.paypal.com/docs/checkout/integration-features/validation/
Combine that with a proper server integration that transmits the values in a fetch body when creating or capturing the order, so your server can store them then.
For that server integration you need to create two routes, one for 'Create Order' and one for 'Capture Order', documented here. These routes should return JSON data.
Pair those routes with the following button approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server , plus your onClick function
Redirect in Django is not working when files are uploaded using Dropzone.js, so I used windows.href in the Dropzone success event but I have to pass a parameter.
views.py:
if request.method == 'POST' and request.FILES['files']:
...
if form.is_valid():
....
user = User.objects.get(email=email)
id = user.id
return redirect(reverse('success', kwargs={'id': id})) <<-- not working
JQuery - Dropzone:
this.on('success', function() {
window.location.href = '/success/';
})
I don't reckon there is a way to pass the id to JQuery in this case, so I have to use redirect in Django. How can it get done?
The reason why django redirect is not working is because dropzone.js uses AJAX for its post requests which doesn't redirect pages.
To get the redirect to work you need to get the dropzone to redirect with javascript to the correct url given as a response from the POST request. The view returns a JSON response that then can be parsed from the js. This is done as follows:
from django.http import JsonResponse
def index(request):
if request.method == 'POST':
form = BenchmarkForm(request.POST, request.FILES)
if form.is_valid():
model_id = YourModel.objects.create(file=request.FILES['file']).id
link = reverse('energy:benchmark',kwargs={'id':model_id})
response = {'url':link}
return JsonResponse(response)
Then in the dropzone init function you need to parse the response in the success callback.
Dropzone.options.myDropzone = {
// Prevents Dropzone from uploading dropped files immediately
autoProcessQueue : false,
url: "{% url 'energy:index' %}",
headers: {
"X-CSRFToken": "{{ csrf_token }}"
},
init : function() {
mydropzone = this;
this.on("success", function(file, response) {
window.location.href=JSON.parse(file.xhr.response).url
});
I'm trying to perform a simple post to django that will take in a variable and then redirect the user to another page. Right now, my javascript looks like this:
$.ajax({
type: "POST",
url: "{% url unity.survey.views.post %}",
data: { // <-- error here?
'order' : '1',
'csrfmiddlewaretoken': '{{ csrf_token }}'
},
success: function(datas) {
if (datas.redirect) {
window.location.href = data.redirect;
}
}
});
};
My corresponding view in django looks like so:
def post(request, *args, **kwargs):
if 'order' in request.POST:
order = request.POST['order']
else:
return redirect('unity.survey.views.login')
.... some calculations with order ....
return render_to_response(
'template.html',
some_dictionary,
context_instance=RequestContext(request)
)
For some reason, it appears that nothing is sent to the view. Looking at Firefox's web console, I see:
[07:31:12.414] POST http://127.0.0.1/unity/ survey/ [undefined 17ms]
[07:31:12.422] GET http://127.0.0.1/unity/survey/ [HTTP/1.1 302 FOUND 73ms]
[07:31:12.497] GET http://127.0.0.1/unity/survey/login [HTTP/1.1 200 OK 177ms]
It just redirects me to the login page regardless of what I do. I've tried using .post instead of .ajax, but it results in the same thing. Any idea why this might be the case? I have a similar function and it works great but for some reason I can't get this to work. It just appears as if no POST data is being sent.