Next.js not receiving cookie from Django - django

I am messing around with Next.js and regular Django to do some testing, study etc.
I am trying to make a basic authentication system that simply takes the email and password, send to the Django server and it simply returns a cookie with the user id.
When I login with valid credentials, the server returns an "OK" (as it is supposed to do), however I don't get any of the cookies I'm supposed to have (not even the default csrf token from Django).
(sample data for design testing)
Using Django 4.0.6 and Next.js 12.3.1
Login route on Django
#csrf_exempt
def login(req):
body = json.loads(req.body.decode("utf-8"))
res = None
if (User.objects.filter(email=body["email"])):
user = User.objects.get(email=body["email"])
if (user.password == body["password"]):
res = JsonResponse({"success": True})
res.status_code = 200
res.set_cookie("AuthToken", json.dumps(
{"id": user.id}),
max_age=60 * 60 * 24,
httponly=False,
samesite="strict",
)
else:
res = JsonResponse({"success": False})
res.status_code = 401
else:
res = JsonResponse({"success": False})
res.status_code = 404
res.__setitem__("Access-Control-Allow-Origin", "*")
print(res.cookies)
return res
My login page on Next
import Link from "next/link";
import { useRouter } from "next/router";
import React, { FormEvent, useState } from "react";
import styled from "styled-components";
import { CONFIG } from "../../../DESIGN_CONFIG";
export default function Login() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const router = useRouter();
async function logIn(e: FormEvent) {
e.preventDefault();
const body = JSON.stringify({ email: email, password: password });
console.log(body);
console.log(process.env.API_URL);
const res = await fetch(process.env.API_URL + "login/", {
method: "POST",
body: body,
});
console.log(res);
if (res.status === 200) {
router.push("/");
}
}
return (
<Background>
<LoginForm onSubmit={logIn}>
<h1>LOGIN</h1>
<label htmlFor="email">E-Mail</label>
<input
type="email"
name="email"
id="email"
onChange={(e) => setEmail(e.target.value)}
required
/>
<label htmlFor="password">Password</label>
<input
type="password"
name="password"
id="password"
onChange={(e) => setPassword(e.target.value)}
required
/>
<button type="submit">Log In</button>
<span>
Or{" "}
<Link href="/user/sign-up">
<a>sign-up</a>
</Link>
</span>
</LoginForm>
</Background>
);
}
// This way down just got the styled-components for background and login form
Prints in the console of the body and the res (and the api route):
I'm using no middleware on Next nor Django and haven't changed anything in the _app.js.
I tried using invalid credentials and got the expected behavior.
I tried using Postman and it gets the cookies.
I tried making a simpler cookie.
res.set_cookie("AuthToken", user.id)

Related

How to upload an image to django from an html input file

I am developing a web service on django with frontend on react. I ran into a problem that I can't upload an image to django. Below is my component code where I'm trying to download it:
export function ProviderRegistration(){
const[logoField, setLogoField] = useState()
const token = useSelector((state) => state.user.token)
const [cookie, setCookie] = useCookies(['auth'])
const confirm = () => {
axios.post(`/providers/?username=${cookie.auth.login}`,
{
photo : logoField
},
{ "headers" : { "Authorization" : "token " + token }})
.then(res => console.log(res))
.catch(err => console.log(err))
}
return(
<div className="registration-provider-container">
<div className="registration-title">Provider registration</div>
<input type="file" className="registration-logo-add" onChange={(e) => setLogoField(e.target.value)}/>
<button className="registration-confirm" onClick={() => confirm()}>Confirm</button>
</div>
)}
And the endpoint processing this request
class Providers(viewsets.ModelViewSet):
filterset_class = ProvidersFilter
queryset = Provider.objects.all()
permission_classes = [IsAuthenticatedOrReadOnly, IsProviderPermission, IsOneToOneProviderPermission]
def get_serializer_class(self):
if self.action == 'list':
return GetProviderSerializer
else:
return PutProviderSerializer
def create(self, request):
username = request.GET.get('username', '')
user = User.objects.get(username=username).pk
request.data.update({'user' : user})
print(request.data)
return super().create(request)
When I try to upload an image, django returns the following error:
"The submitted data was not a file. Check the encoding type on the form."
And I haven't found a way to correctly upload an image to django using Ajax.
I also output what my browser sends to the server:
{photo : 'C:\\fakepath\\magnit.jpg'}

Django backend configuration to Stripe, React frontend

I have created React frontend for Stripe payment, how can I configure Django Rest Framework server ?
REACT COMPONENT
import React, { Fragment } from "react";
import StripeCheckout from "react-stripe-checkout";
import axios from "axios";
const StripeBtn = () => {
const publishableKey = "pk_test_some key";
const onToken = token => {
const body = {
amount: 999,
token: token
};
axios
.post("http://localhost:8000/payment", body)
.then(response => {
console.log(response);
alert("Payment Success");
})
.catch(error => {
console.log("Payment Error: ", error);
alert("Payment Error");
});
};
return (
<StripeCheckout
label="Go Premium" //Component button text
name="Business LLC" //Modal Header
description="Upgrade to a premium account today."
panelLabel="Go Premium" //Submit button in modal
amount={999} //Amount in cents $9.99
token={onToken}
stripeKey={publishableKey}
image="" //Pop-in header image
billingAddress={false}
/>
);
};
export default StripeBtn;
Regular Django views, instead of this I need Django Rest framework code to receive the axios POST request.
def charge(request): # new
if request.method == 'POST':
charge = stripe.Charge.create(
amount=500,
currency='usd',
description='A Django charge',
source=request.POST['stripeToken']
)
return render(request, 'payments/charge.html')
I have installed Stripe in Django and added key's in settings.py and above view is regular Django function to receive Stripe payments.
I was following a tutorial but they were using express.js as backend
https://medium.com/hackernoon/stripe-api-reactjs-and-express-bc446bf08301

Uploading a CSV or Excel file along with json data through React html form to Django

I want to submit a form to upload either a csv file or an excel file, and provide additional information provided in the form, e.g. text.
For defining the form and sending the request I use React Bootstrap with axios, and for the api I'm using Django 2.2 with rest-framework.
request.FILES is always an empty dict, even if I try setting the Content-Type header to multipart/form-data, and then additionally nothing is found in the post data of the request, and printing request.data.get('information') below shows None in the Django log. Please help, any support will be greatly appreciated.
See below for code snippets.
Form definition in render():
<form onSubmit={this.handleSubmit}>
<FormGroup>
<Form.Label>Upload file</Form.Label>
<Form.Control type="file" onChange={this.handleFile}></Form.Control>
</FormGroup>
<Button block bssize="large" disabled={!this.validateForm()} type="submit">
Submit
</Button>
</form>
Handling file change:
handleFile = event => {
event.preventDefault();
const fileToUpload = event.target.files[0]
this.setState({
fileToUpload: fileToUpload
})
}
Sending the request:
const payload = {
file: this.state.fileToUpload,
information: "somedata"
}
const contentType = "multipart/form-data"
let accessToken = token
var headers = {"Authorization" : `Bearer ${accessToken}`}
headers['Content-Type'] = contentType
const response = await axios({
method: "post",
data: payload,
url: url,
headers: headers
});
Django endpoint definition:
class RegisterData(views.APIView):
parser_classes = (parsers.JSONParser, parsers.MultiPartParser)
def post(self, request):
for file in request.FILES.values():
print(file)
info = request.data.get('information')
print(info)
return Response({"success": "Good job, buddy"})
The answer is in the comments but I'll put it here so it's more visible to users with these issues:
Check that you are using the correct data types and arguments for axios:
How to post a file from a form with Axios

How to upload File from Angular 7 to Django - get error 403 (Forbidden)

I tried now in so many different ways, I can not get a file uploaded with Angular 7 to the Django Backend - shouldn't be so difficult?!
My .html:
<div class="form-group">
<label for="file">Choose File</label>
<input type="file"
id="file"
(change)="handleFileInput($event.target.files)">
</div>
uploader.component.ts
fileToUpload: File = null;
handleFileInput(files: FileList) {
this.fileToUpload = files.item(0);
this.uploadFileToActivity();
}
uploadFileToActivity() {
this.uploaderService.post(this.fileToUpload).subscribe(data => {
// do something, if upload success
}, error => {
console.log(error);
});
}
my uploader.service.ts that also shows the upload progress
public post( fileToUpload: File): Observable<number>{
const url = '/api/upload/';
var subject = new Subject<number>()
const req = new HttpRequest('POST', url, fileToUpload, {
reportProgress: true,
});
this.httpClient.request(req).subscribe(event => {
if (event.type === HttpEventType.UploadProgress) {
const percentDone = Math.round(100 * event.loaded / event.total);
subject.next(percentDone);
} else if (event instanceof HttpResponse) {
subject.complete();
}
});
return subject.asObservable();
}
And in the Django backend:
views.py:
def post(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
#handle_uploaded_file(request.FILES['file'])
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render(request, 'index.html', {'form': form})
forms.py:
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
file = forms.FileField()
and urls.py:
urlpatterns = [
path(r'api/upload/', views.post, name='post'),
]
When I ran this I get
zone.js:2969 POST http://127.0.0.1:8000/api/upload/ 403 (Forbidden)
Do I need to include an authorization token? If yes: how?
Thanks a lot!
EDIT: After the useful input from Martin Urbanec I inspected the file upload request in the Browser. Here the result:
Someone any idea what I need to change in my code above to make this work?
Content-Type header must be multipart/form-data to transfer any files. I recommend you to check if this header is sent to your Django backend.

I'm trying to get a rest resource to a python server with Ionic 3

How to title I'm trying to get a rest resource from a server.In particular I must post some data to the server(user and password) and If the request is successfull I simply print "Success" otherwise "error".When I make the request my server answer me with a code 200(which make me think that everything has come to and end) but in my ionic web page I found this error "Failed to load http://127.0.0.1:5000/: Request header field Access-Control-Allow-Origin is not allowed by Access-Control-Allow-Headers in preflight response".I tried to solve this problem implementing the crossdomain in my server as recommended by several guides but I could not get anything.I also tried to reach the rest resource using in my terminal the comand "curl POST --data "user=0124000769&password=dfgdsfgs" --verbose http://127.0.0.1:5000 " and this return me the right result so I think my server is working fine.To implement the user interface I'm using Ionic 3 framework.Thank you all in advance.Excuse me for my English.This is my code in Ionic:
login.ts:
#Component({
selector: 'page-home',
templateUrl: 'login.html'
})
export class LoginPage {
private mat:string;
private pass:string;
constructor(public navCtrl: NavController,public http: Http) {}
postRequest(){
var headers = new Headers();
headers.append("Accept","application/json");
headers.append("Content-Type","application/json");
headers.append('Access-Control-Allow-Origin', '*');
let options = new RequestOptions({headers:headers});
let postParams = {
mat:this.mat,
pass:this.pass
};
this.http.post("http://127.0.0.1:5000/",postParams,options).subscribe(data=>{
console.log("OK")},error2 => {
console.log("Error")
});
}
}
login.html:
<ion-header>
<ion-navbar>
<ion-title>
Login Page
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding id="page1">
<form id="page-form2">
<ion-item id="page-input3">
<ion-label>
Matricola
</ion-label>
<ion-input type="text" placeholder="" [(ngModel)]="mat" name="matricola"></ion-input>
</ion-item>
<ion-item id="page-input4">
<ion-label>
Password
</ion-label>
<ion-input type="password" placeholder="" [(ngModel)]="pass" name="password"></ion-input>
</ion-item>
</form>
<button id="page-button2" ion-button color="positive" block (click)="postRequest()">
Login
</button>
</ion-content>
This is the code of my server
My rest Resource:
#app.route('/',methods=['POST','OPTIONS'])
#crossdomain(origin='*')
def login():
username = request.get('mat')
password = request.get('pass')
s = Scraper(username, password)
return jsonify(s.login())
My crossdomain:
def crossdomain(origin=None, methods=None, headers=None, max_age=21600,
attach_to_all=True, automatic_options=True):
"""Decorator function that allows crossdomain requests.
Courtesy of
https://blog.skyred.fi/articles/better-crossdomain-snippet-for-flask.html
"""
if methods is not None:
methods = ', '.join(sorted(x.upper() for x in methods))
if headers is not None and not isinstance(headers, basestring):
headers = ', '.join(x.upper() for x in headers)
if not isinstance(origin, basestring):
origin = ', '.join(origin)
if isinstance(max_age, timedelta):
max_age = max_age.total_seconds()
def get_methods():
""" Determines which methods are allowed
"""
if methods is not None:
return methods
options_resp = current_app.make_default_options_response()
return options_resp.headers['allow']
def decorator(f):
"""The decorator function
"""
def wrapped_function(*args, **kwargs):
"""Caries out the actual cross domain code
"""
if automatic_options and request.method == 'OPTIONS':
resp = current_app.make_default_options_response()
else:
resp = make_response(f(*args, **kwargs))
if not attach_to_all and request.method != 'OPTIONS':
return resp
h = resp.headers
h['Access-Control-Allow-Origin'] = origin
h['Access-Control-Allow-Methods'] = get_methods()
h['Access-Control-Max-Age'] = str(max_age)
h['Access-Control-Allow-Credentials'] = 'true'
h['Access-Control-Allow-Headers'] = \
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
if headers is not None:
h['Access-Control-Allow-Headers'] = headers
return resp
f.provide_automatic_options = False
return update_wrapper(wrapped_function, f)
return decorator
My Login function:
def login(self) :
result = {'login': '0' }
url = 'my_url'
//There is some action to control the data;
if not value :
return result
result['login'] = '1'
#Codifica 'result' in formato JSON
return json.dumps(result)
if you use chrome try to use --disable-web-security option.
Use this on terminal:
open -n -a /Applications/Google\ Chrome.app --args --user-data-dir="/tmp/someFolderName" --disable-web-security