CSRF verification failed. Request aborted [New] 2021 - html

I am completely tired with the csrf issue. I have created a sign in form and register form.
I am able to login and logout, even register a user.
The main problem I am facing is the refresh-after-signin.
After signing in, if I refresh the page it simply gives a csrf verification failed error.
I have literally searched for it since past two days with no solution, all the answers are almost 4-5 years older, which are not helping.
This is the views.py signin function.
def signin(request):
if request.method=="POST":
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username,password=password)
if user is not None:
login(request,user)
messages.success(request,"Logged in Successfully!")
return render(request,'authtest/index.html')
else:
messages.error(request,"Bad Credentials")
return redirect('index')
return render(request,'authtest/signin.html')
This is the HTML form that is returning POST request
<form action="{% url 'signin' %}" method="POST">
<!-- I have no idea what this thing does -->
{% csrf_token %}
<!-- I have no idea what this thing does end -->
<input type="hidden" id="csrf_token" value='{"csrfmiddlewaretoken": "{{ csrf_token }}"}'>
<label for="username">UserName</label>
<input type="text" name="username" id="username" required>
<label for="password">Password</label>
<input type="password" name="password" id="password" required>
<button type="submit">SignIn</button>
</form>

Due to some security issues to keep each user's session safe, it is not possible to authenticate and render the url in the same view functions.
Therefore, you must perform the rendering operation in another URL after redirecting
something like this
def signin(request):
if request.method=="POST":
........
if user is not None:
..........
return redirect ('dashboard')\
and that dashboard func is like this
def dashboard(request):
.......
return redirect ('dashboard')

Related

Online waiting: django submit form and display result in same page

I have an emergent task to make a web page which allow user to input some data and the backend do some calculation and the result needs to be displayed in the same page just below the input field (like air ticket online price check).
I am new to django and html. below is my first test web page of a simple online calculator to try to figure out how to make such web service.
I found a problem that when clicking the "submit" button, it tends to jump to a new web page or a new web tab. this is not what I want. Once the user input the data and click "submit" button, I want the "result" field on the page directly show the result (i.e. partially update only this field) without refresh/jump to the new page. Also I want the user input data kept in the same page after clicking "submit".
I saw there might be several different ways to do this work, iframe/AJAX. However, I have been searching/trying for answers and solutions for several days and none of the answers really work for this very basic simple question!!
html:
<form method="POST">
{% csrf_token %}
<div>
<label>num_1:</label>
<input type="text" name="num_1" value="1" placeholder="Enter value" />
</div>
<div>
<label>num_2:</label>
<input type="text" name="num_2" value="2" placeholder="Enter value" />
</div>
<br />
<div>{{ result }}</div>
<button type="submit">Submit</button>
</form>
view.py
def post_list(request):
result = 0
if request.method == "POST":
num1 = request.POST.get('num_1')
num2 = request.POST.get('num_2')
result = int(num1) + int(num2)
print(request.POST)
print(result)
context = {
'result': result
}
return render(request, 'blog/post_list.html', context)
I would suggest taking a look at htmx.org which makes this really simple without having to write any actual JS.
For your example:
(1) You add the htmx JS (which is only about 10k) to your HTML, and use hx-post and hx-target to trigger the ajax calls on your form. With these the form will fire an AJAX request, and the hx-target tells htmx to take the response (which you want to be only the result of your calculation) and put it in the div without refreshing the whole page.
See docs for more details on this.
Note also I gave an id to the div containing the result.
You will need to replace hx-post="{% url 'blog:post_list' %}" with the correct name to your view (which we don't know as you didn't post your urls.py).
<html>
<body>
<form method="POST" hx-post="{% url 'blog:post_list' %}" hx-target="#result">
{% csrf_token %}
<div>
<label>num_1:</label>
<input type="text" name="num_1" value="1" placeholder="Enter value" />
</div>
<div>
<label>num_2:</label>
<input type="text" name="num_2" value="2" placeholder="Enter value" />
</div>
<br />
<div id="result">{{ result }}</div>
<button type="submit">Submit</button>
</form>
<script src="https://unpkg.com/htmx.org#1.6.1"></script>
</body>
</html>
(2) In your view then you determine if the request is an AJAX request from htmx by checking the headers, in which case you want to only return the result. There are easier or elegant ways to do this (eg. check django-htmx, but just to keep it simple:
from django.http.response import HttpResponse
from django.shortcuts import render
# Create your views here.
def post_list(request):
result = 0
if request.method == "POST":
num1 = request.POST.get('num_1')
num2 = request.POST.get('num_2')
result = int(num1) + int(num2)
if request.headers.get('Hx-Request') == 'true':
# return only the result to be replaced
return HttpResponse(str(result))
else:
return render(request, 'blog/post_list.html', {'result': result})

(DJANGO) retrieving data from html form using GET/POST

This is part of the CS50W courseware Project 1. I have tried to retrieve a user input from a form using a get method. However, the search_query variable in views.py does not have any input. I then changed the get methods to post methods and it worked. Why is that so?
layout.html (GET method)
<form action="{% url 'search' %}" method="GET">
<input type="search" name="search_query" placeholder="Search Encyclopedia">
</form>
views.py (GET method)
def search(request):
search_query = request.GET['search_query']
if search_query in util.list_entries():
return redirect('entry_page', title=search_query)
for entry in util.list_entries():
if search_query in entry:
return redirect('search_results')
layout.html (POST method)
<form action="{% url 'search' %}" method="POST">
{% csrf_token %}
<input type="search" name="search_query" placeholder="Search Encyclopedia">
</form>
views.py (POST method)
def search(request):
search_query = request.POST['search_query']
if search_query in util.list_entries():
return redirect('entry_page', title=search_query)
for entry in util.list_entries():
if search_query in entry:
return redirect('search_results')
I think this is due to differences in the nature of http requests. In POST requests we send the data separately, but in GET requests we have to put them in the url. You probably expect form to do this for you, but it does not! This means that this form will not put the parameters in the url in GET mode.

django inserting data into db using html template

I'm new in django. I'm trying to connect already made an html file to django backend without rebuilding whole file.
Already created forms and views in python but have no idea what to put into html file.
view class:
class signup(View):
template = loader.get_template('signup.html')
form_class = UserRegistrationForm
def get(self, request):
form = self.form_class(None)
return render(request, 'signup.html', {'form': form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
current_user = form.save(commit=False)
email = form.cleaned_data['email']
password = form.cleaned_data['password']
current_user.set_password(password)
current_user.save()
userToAuthenticate = authenticate(email=email, password=password)
if userToAuthenticate is not None:
if userToAuthenticate.is_active:
login(request, userToAuthenticate)
return redirect('siteViews:index')
return render(request, 'signup.html', {'form': form})
form code:
class UserRegistrationForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['email', 'password']
and html code:
<div id="registersquare">
<div id="panel">
<form class="form-horizontal" role="form" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<label for="email">Email adress:</label>
<input type="email" id="username" name="email}">
<label for="password">Password:</label>
<input type="password" id="password" name="password">
<label for="password">Repeat password:</label>
<input type="password" id="password" name="repeatedpassword">
<label class="control-label col-sm-2" for="password">{{ field.label_tag }}</label>
<div id="lower">
<input type="checkbox"><label class="check" for="checkbox"><a style="color: #999999;" href="#">I Accept Website Terms And Conditions.</a></label>
<input type="submit" value="Sign up">
</div>
</form>
</div>
</div>
anyone can explain how to do it?
cheers
You hav already created a Form, which is not Django's form, so you dont actually have to write anything in forms.py, as the purpose of it is to create an form based on the model structure and perform validations according to the fields defined.
Now you have to fetch data from form and perform the validation and checks by yourself in views. So the post would be
def post(self, request):
email = request.POST.get('email') # get value in name="email" field
password = request.POST.get('password')
repeatedpassword = request.POST.get('repeatedpassword')
if password == repeatedpassword: # manual validation to check if both string are same
# Other Validations code here and
# Register or Login etc functions here
return render(request, 'signup.html', {'form': form})
You need to delete the labels and inputs from your html file and add this tag after the {% csrf_token %}, {{form.as_p}}, that's a start. You are also using an older version of Django, the way I can tell is because when you defined your ModelForm you wrote forms.ModelForm when it has been changed to just ModelForm, to upgrade write
pip install -U Django
You essentially created two forms, one with just html and one with Django only you did not apply your ModelForm to your html file instead you just made a html form instead of a html rendered Django ModelForm.

Symfony3: Login form does not work when rendered on another site

I want to login on the homepage instead of separate site. When I type my credentials in /login route, everything is okay, but it does not work on the / route.
I render login form with this command in base.html.twig (for testing purposes I want to render login form at each page now):
{{ render(controller("AppBundle:Security:login")) }}
Here is my login.html.twig:
{% if error %}
<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
<form action="{{ path('login') }}" method="post">
<div class="form-group">
<input type="text" class="form-control" id="username" placeholder="Email" name="_username" value="{{ last_username }}" />
<input type="password" class="form-control" id="password" placeholder="Heslo" name="_password" />
</div>
<button type="submit" class="btn btn-success">Přihlásit</button>
Registrovat
</form>
And my loginAction:
/**
* #return array
* #Route("/login", name="login")
* #Template()
*/
public function loginAction()
{
$authenticationUtils = $this->get('security.authentication_utils');
// get error
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return [
'last_username' => $lastUsername,
'error' => $error
];
}
And secured_area in security.yml:
secured_area:
pattern: ^/
anonymous: ~
provider: main
form_login:
login_path: login
check_path: login
logout:
path: /logout
target: /
The login form successfully renders at homepage. But nothing happen when I enter the credentials and click the button. Maybe because the button tries to find a form in action defined for homepage instead of action defined for login page?
Is there an option to "force" the button to use original (login) action instead?
Thank you for your answers.
You should post the login form to the check_path configured in your security.yml, not to the controller displaying your login form.
It is this URL (which is intercepted entirely by the security extension) that will authenticate the user, and if an error occurs, will redirect the user back to the login action.
For detailed instructions on how to set-up form based login, check the dedicated cookbook article in the documentation: http://symfony.com/doc/current/cookbook/security/form_login_setup.html

Email sending in django code is not working

Email sending in django code is not working,
it display error "[Errno 10061] No connection could be made because the target machine actively refused it"
these are my VIEWS.PY
def send_email(request):
username = request.POST.get('username', '')
from_email = request.POST.get('from_email', '')
message = request.POST.get('message', '')
if username and message and from_email:
try:
send_mail(username, from_email, message, ['canonizadocharm#ymail.com'])
except BadHeaderError:
return HttpResponse('Invalid header found.')
return HttpResponseRedirect('/contact/thanks/')
else:
# In reality we'd use a form class
# to get proper validation errors.
return HttpResponse('Make sure all fields are entered and valid.')
these are my contact.html
<FORM METHOD="POST" ACTION="/send_email/" >
{% csrf_token %}
Name: <INPUT TYPE="text" NAME="username"><BR>
Email: <INPUT TYPE="text" NAME="from_email"><BR>
Message: <BR>
<TEXTAREA NAME="message" ROWS="10" WRAP="hard">
</TEXTAREA>
<INPUT NAME="redirect" TYPE="hidden">
<INPUT NAME="NEXT_URL" TYPE="hidden">
<BR>
<INPUT TYPE="submit" VALUE="Send">
<INPUT TYPE="reset" VALUE="Clear">
</FORM>
these are my URLS.PY
url(r'^send_email/', views.send_email),
url(r'^contact/', views.contact),
url(r'^thanks/', views.thanks),
and my SETTINGS.PY
EMAIL_HOST = 'localhost'
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_PORT = 25
EMAIL_USE_TLS = True
Your action value of form must direct to view's url, mailto:canonizadocharm#ymail.com is not a valid path on your server.
UPDATED:
For example, add a new rule to urls.py like,
url(r'^mail/', views.send_mail),
Then change action value to mail.
Have your action value point to a URL, which in turn points to one of your views. For instance, your urls.py can do this.
url(r'^email/', 'project.views.send_email')
This will route your contact form to your send_mail view.
Your form in the templates has no csrf that's why you get an error of "CSRF verification failed".
<FORM METHOD=POST ACTION="/send_email/" ENCTYPE="text/plain">{% csrf_token %}
...........
</FORM>
If you want to know what is csrf just go to this link:
https://docs.djangoproject.com/en/dev/ref/contrib/csrf/
Create email setting in your settings.py, like this for example:
settings.py
# Sending mail
EMAIL_USE_TLS = True
EMAIL_HOST='smtp.gmail.com'
EMAIL_PORT=587
EMAIL_HOST_USER='your gmail account'
EMAIL_HOST_PASSWORD='your gmail password'
views.py
from django.core.mail import send_mail
def send_email(request):
if request.method == 'POST':
username = request.POST.get('username')
message = request.POST.get('message')
from_email = request.POST.get('from_email')
send_mail(username, message, from_email, ['canonizadocharm#ymail.com',])
return HttpResponseRedirect('/contact/thanks/')
else:
return HttpResponse('Make sure all fields are entered and valid.')