I'm writing an enrollment website for my school, and using Django for the framework. For the registration, I require a username, password, and registration token. Those have yet to be validated, all I'm attempting to do right now is go from the registration input page (which uses a POST request) to a "You have successfully registered" page. Somewhere along the line, the csrf token is apparently refusing to be validated.
My view:
def register(request):
return render(request, 'enroller/successfulEnroll.html')
My page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="{% url 'register' %}" method="post"> {% csrf_token %}
<div class="container">
<label><b>New Username</b></label>
<input type="text" placeholder="Username" name="uname" required>
<br>
<label><b>Password</b></label>
<input type="password" placeholder="Password" name="psw" required>
<br>
<label><b>Registration Password</b></label>
<input type="text" placeholder="Registration Key" name="reg" required>
<br>
<input type="submit" value="Register" />
</div>
</form>
</body>
</html>
When I attempt to go from the registration page to the success page, it gives me an error 403 (CSRF Verification failed. Request aborted). However, when I attempt to go to the url mysite.com/register/, it returns the page I requested with no error.
Is there any way to fix this? I've been looking at RequestContext, but I'm not entirely sure where it would be used.
Got it to work. Daniel was right - it was a problem with the configuration of my middleware. I added two lines before my middleware array in settings.py, and all of the sudden it worked.
SESSION_COOKIE_SECURE = True
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
I can't say I'm entirely sure why it worked, or what the issue was exactly, but it works now. Thanks Daniel!
maybe you can use this method. And djang version is 1.11.1
from django.shortcuts import render
from django.template.context_processors import csrf
form = LoginForm()
c = {'form': form}
c.update(csrf(request))
return render(request, 'a_template.html', c)
I found this method at http://djangobook.com/security-in-django/
For me, work fine, but not the best, because more than a line.
Related
I am building a website in django. I used login_required decorator to prevent user to move to UserView without a successful login. But I came to problem where its not moving from login page even after a successful login authentication and stays on the login page. What am I doing wrong?
Here is my code:
view.py
def LoginView(request):
if request.method=='POST':
username=request.POST.get('username')
password=request.POST.get('password')
try:
user_info=User_Registration.objects.get(username=username)
if user_info.password==password:
return redirect("userview")
else:
messages.info(request,"Invalid Password")
except User_Registration.DoesNotExist:
messages.info(request,"User Doesn't exist")
else:
return render(request,'login.html')
#login_required(login_url="login_view")
def UserView(request):
return render(request,'user.html')
urls.py
from django.urls import path
from post_app import views
urlpatterns=[
# path('',views.MainPageView.as_view()),
path('/login',views.LoginView,name='login_view'),
path('/userview',views.UserView,name='userview'),
path('/registration',views.RegistrationView,name='registration_view'),
path('new_job/<str:id>',views.post_new_job,name='new_job')
]
login.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link rel="stylesheet" href="{% static 'login.css' %}">
<!------ Include the above in your HEAD tag ---------->
<body>
<div id="login">
<h3 class="text-center text-white pt-5">Login form</h3>
<div class="container">
<div id="login-row" class="row justify-content-center align-items-center">
<div id="login-column" class="col-md-6">
<div id="login-box" class="col-md-12">
<form id="login-form" class="form" action="" method="POST">
{% csrf_token %}
<h3 class="text-center text-info">Login</h3>
<div class="form-group">
<label for="username" class="text-info">Username:</label><br>
<input type="text" name="username" id="username" class="form-control">
</div>
<div class="form-group">
<label for="password" class="text-info">Password:</label><br>
<input type="password" name="password" id="password" class="form-control">
</div>
<div class="form-group">
<input type="submit" name="submit" class="btn btn-info btn-md" value="submit">
</div>
<div id="register-link" class="text-right">
Register here
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<div>
{% for message in messages %}
<br>
<h2 style="padding-left: 500px;" >{{message}}</h2>
{% endfor %}
</div>
</body>
</html>
Your code doesn't follow best practices for implementation of Authentication/Authorization in Django. Anyway, let me show how to fix your existing code to make it working.
def LoginView(request):
if request.method=='POST':
username=request.POST.get('username')
password=request.POST.get('password')
try:
user_info=User_Registration.objects.get(username=username)
if user_info.password==password:
return redirect("userview")
else:
messages.info(request,"Invalid Password")
except User_Registration.DoesNotExist:
messages.info(request,"User Doesn't exist")
return render(request,'login.html')
#login_required(login_url="login_view")
def UserView(request):
return render(request,'user.html')
So what was wrong? In the case when User Doesn't Exist or Invalid Password was entered - you do nothing, just add an error message. When the message is added you should render the template, where you will iterate over all messages. More about messages here https://docs.djangoproject.com/en/3.1/ref/contrib/messages/#enabling-messages
In the meantime, this still can be not working as expected. I have a set of questions to you:
Do you get the password in raw format? I mean just a string with password, without hashing and any other protection.
How do you store passwords in User_Registration model? Is it also just a string with password or the hashed string?
I also have a long list of further improvements in your code, but let's figure out the bug first.
UPDATE (22.09.2020)
Since you get page refresh and you're still on the login page - I think that redirect code wasn't called. That means you should see one of those messages you add. Please try to add messages to the context during template rendering. And let's check what messages you will see.
def LoginView(request):
if request.method=='POST':
username=request.POST.get('username')
password=request.POST.get('password')
try:
user_info=User_Registration.objects.get(username=username)
if user_info.password==password:
return redirect("userview")
else:
messages.info(request,"Invalid Password")
except User_Registration.DoesNotExist:
messages.info(request,"User Doesn't exist")
return render(request,'login.html', {
'messages': messages.get_messages(request)
})
#login_required(login_url="login_view")
def UserView(request):
return render(request,'user.html')
If still you will not get any message, we can try replace both messages.info with raise. So the application will fail in one the places. But let's try passing messages explicitly first.
The checklist for getting messages to work https://docs.djangoproject.com/en/dev/ref/contrib/messages/#enabling-messages
'django.contrib.messages' is in INSTALLED_APPS
MIDDLEWARE contains 'django.contrib.sessions.middleware.SessionMiddleware' and 'django.contrib.messages.middleware.MessageMiddleware'.
The 'context_processors' option of the DjangoTemplates backend defined in your TEMPLATES setting contains 'django.contrib.messages.context_processors.messages'
views.py:
#login_required
def UserView(req):
return render(req,"user.html")
setting.py:
LOGIN_URL = '/accounts/login/' #Define your login page url..
Redirct method accepts 3 types of arguments;
A model: the model’s get_absolute_url() function will be called.
A view name, possibly with arguments: reverse() will be used to reverse-resolve
the name.
An absolute or relative URL, which will be used as-is for the redirect location.
Make sure that you are using correct view name.
In your views.py:
if user_info.password == password: # I am not sure this is good way.
return redirect("userview") # You cannot login here. If password equal password. This will redirect userview without login
Please use like this:
from django.contrib.auth import login, authenticate # You need add this functions
def LoginView(request):
if request.method=='POST':
username=request.POST.get('username')
password=request.POST.get('password')
user = authenticate(username=username, password=password) # You can control user with this function. If username and password are correct, this function will return this user. If incorrect, this will return None.
if user is None:
messages.info(request,"Username or password incorrect")
return redirect("login_view")
else:
login(request, user) # You can login with this function
messages.success(request, "You have successfully logged in")
return redirect("userview")
return render(request,'login.html')
#login_required(login_url="login_view") # And now You can access this view. Because you logged in with login function
def UserView(request):
return render(request,'user.html')
My English skill is not good, but i tried to explain.
After researching a for the similar problems, You can try:
Removing cache from the browser.
Also, as login url is static for the website. You can define your login_url in settings.py like:
LOGIN_URL = '/post_app/login'
Then, you don't have to define the login_url everywhere you use it. Else, everything looks good.
I'm working on the django authentification request and I get the forbidden error I checked my code but it doesn't seem I'm having an error.
HTML
<div class="grad"></div>
<div class="header">
<div>MLAT<span>SI</span></div>
</div>
<form action="{{views.login_user}}" method="POST">{% csrf_token %}
<div class="login">
<img src="{% static "img/Airplane.png" %}">
<div id="h" class="home">
<input type="text" placeholder="Login" name="username" value="">
<input type="password" placeholder="Mot de passe" name="password" value="">
<input style="float: left; width: 173px" type="submit" value="Log in" >
<input formaction="/form_registration.html/" style="float: right; width: 173px" type="submit" value="Register">
views.py
def login_user(request):
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(username=username, password=password)
if user is not None and user.is_active:
login(request, user)
return HttpResponse("You're logged in.")
else:
return HttpResponse("Your username and password didn't match.")
you seem like you have a problem in the import package. And the way you're calling the views are incorrect you should read the Django documentation well
Looks like a duplicate of: Django - {% csrf_token %} was used in a template, but the context did not provide the value
Basically, your login_user view isn't making use of any render/context, hence the error (I don't know if that's the same view that is called when the url for login is called). So Django sees the csrf_token but never converts it to an actual token value.
from django.shortcuts import render
But really both your form and view look very wrong. The form action {{ views.login_user }} is incorrect. You can't call a view that way. And your Register button goes to what looks like an HTML page.
Hi I got a simple form for a POST request and it works when I'm only having one input, but not two inputs together. Can someone show me some light on this?
index.html
<form name="input" action="{% url 'sending' %}" method="post">
{% csrf_token %}
Recipient: <input type="text" name="recipient">
<br>
Message: <input type="text" name="content">
<br>
<input type="submit">
</form>
views.py
def sending(request):
recipient = request.POST.get('recipient','')
content = request.POST.get('content','') #not working when I am doing this...
someMethod(recipient, content)
return HttpResponseRedirect(reverse('results'))
Adding a "forms" portion to your setup will help you greatly... see the quickstart docs on forms here: https://docs.djangoproject.com/en/1.6/topics/forms/
In particular, check out "using a form in a view": https://docs.djangoproject.com/en/1.6/topics/forms/#using-a-form-in-a-view
Basically, you end up with a "forms.py" file which defines your form fields. Then, after it all processes, you get a simplier API into your form fields that looks like this:
form.cleaned_data['recipient']
form.cleaned_data['content']
etc.
i am trying to do a login in django but i get this error, i check the CSRF documentation and nothing works for me.
Here is the HTML:
<body>
<section class="container">
<div class="login">
<h1>Login to Web App</h1>
{% if form.errors %}
<p class="error">Lo sentimos, la combinacion de usuario y contrasena no es correcta!</p>
{% endif %}
<form action="/accounts/auth/" method="post">
{% csrf_token %}
<input type='hidden' name='csrfmiddlewaretoken' value='randomchars'/>
<p><input name="username" type="text" name="login" value="" placeholder="Username"></p>
<p><input name="password" type="password" name="password" value="" placeholder="Password"></p>
<p class="submit"><input type="submit" name="commit" value="Login"></p>
</form>
</div>
</body>
Like you see above i use the {% csrf_token %} and i have 'django.middleware.csrf.CsrfViewMiddleware' in my installed apps.
And my views are:
from django.http import HttpResponse,HttpResponseRedirect
from django.template.loader import get_template
from django.template import Context
from datetime import datetime
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.contrib import auth
from django.core.context_processors import csrf
from models import *
from django.shortcuts import get_object_or_404
from forms import *
from django.template.context import RequestContext
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate, login
def login(request):
c = {}
c.update(csrf(request))
return render_to_response('login.html', c)
def auth_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
auth.login(request.user)
return HttpResponse('/accounts/loggedin')
else:
return HttpResponse('/accounts/invalid')
i redirect to an other HTML file where i dont use the {% csrf_token %}.
Theory
A couple of things are required to make the csrf protection work (check out the docs):
Your browser has to accept cookies from your server
Make sure you have 'django.middleware.csrf.CsrfViewMiddleware' included as middleware in your settings.py (alternatively use the decorator csrf_protect() on particular views you want to protect)
Make sure you pass on the csrf token from django.core.context_processors.csrf to the context manager.
When you load your page, have a look in the page source using your favorite browser. Don't open the template html file, open the url which point to the view containing the form. Look at where you placed the {% csrf_token %}. If you see something like
<input type='hidden' name='csrfmiddlewaretoken' value="jdwjwjefjwdjqwølksqøwkop2j3ofje" />
you should be ok.
If you on the other hand see NOTPROVIDED, something has gone wrong while creating the csrf token. By looking in the source code (context_processors.py and csrf.py), we can find out what:
csrf(request) returns {'csrf_token': 'NOTPROVIDED'} if get_token(request) returns None.
get_token(request) returns request.META.get("CSRF_COOKIE", None).
I assume this means that it would return None if the cookie isn't successfully created.
Fix
For you, this means that you should first replace
<form action="/accounts/auth/" method="post" {% csrf_token %}>
with
<form action="/accounts/auth/" method="post">
{% csrf_token %}
(...)
</form>
We'd like the csrf field to be inside <form>...</form>, not inside <form>. As the code is at the moment, it will be converted to
<form action="/accounts/auth/" method="post" <input type='hidden' name='csrfmiddlewaretoken' value='randomchars' />>
and we would rather like
<form action="/accounts/auth/" method="post">
<input type='hidden' name='csrfmiddlewaretoken' value='randomchars' />
After that - have a look at the source code, and see if you can find the csrf field. If you can see it, everything should work in theory.
You can also check that the csrf cookie has been set in your browser, e.g. in Chrome, right-click the web page, and select Insepect Element. Select the Resources tab, and click on cookies. You should find a cookie name csrftoken there.
If you still have problems, double-check the middleware tuple in your settings.py and double-check that your browser accept cookier from your server as described above.
Clear your browser cache and try again. Maybe it is using the CSRF token saved in cached cookie.
With Addition of above answer, Try Adding following lines in the views
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def somathing():
return something
I added django.contrib.auth.views.login everywhere in my webpage, for that I had to load a templatetag (that returns the AuthenticationForm) in my base.html. This templatetags includes the registration/login.html template.
The login is working ok but I want it to redirect the users to the same page they are before login. Now, it redirects me to /wherever_i_am/login wich shows registration/login.html with the 'login ok' or 'login fails' messages but without the rest of base.html.
I have followed django documentation and a few SO questions like this but I cannot redirect correctly. I have modified the next variable but it doesn't seem to work (next={{ request.get_full_path }} redirects me to /wherever_i_am/login ...again)
Have you tried something similar? any ideas?
UPDATE1
Now, the question could be something like: Do I have to declare my own login view if I want to include the login form everywhere in my web page?
Thank you.
Found answer:
Change settings.LOGIN_REDIRECT_URL in your settings.py,
below code is copy from django:
if request.method == "POST":
form = authentication_form(data=request.POST)
if form.is_valid():
# Ensure the user-originating redirection url is safe.
if not is_safe_url(url=redirect_to, host=request.get_host()):
redirect_to = settings.LOGIN_REDIRECT_URL
...
The below allows redirects the user to the page they were attempting to access after they log in, but without having to write a custom view. It contains all the code you need to add to make it work. (As an aside, not all the TEMPLATE_CONTEXT_PROCESSORS are needed, but if you set a value to it explicitly you overwrite the defaults so need to re-add them.)
settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.request",
"django.core.context_processors.static",
)
urls.py
from django.contrib.auth.views import login, logout
...the other imports for your app ...
urlpatterns = patterns('',
(r'^login/$', login, {'template_name':'login.html'} ),
(r'^logout/$', logout,{'template_name':'logout.html'}),
...the other urls for your app...
)
login.html
<html>
<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
{% csrf_token %}
{{form}}<br/>
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
</html>
logout.html
<html>
<p>You are logged out. To log in again, click here.</p>
</html>
views.py
#login_required(login_url="/login/")
def view1(request):
....this is a view you want to protect with security...
#login_required(login_url="/login/")
def view1(request):
....this is a view you want to protect with security...
I used something like this with default login view:
{% if form.errors %}
<p class="error">Sorry, that's not a valid username or password</p>
{% endif %}
<form action="{% url login %}" method="post">
{% csrf_token%}
<label for="username">User name:</label>
<input type="text" name="username" value="" id="username">
<label for="password">Password:</label>
<input type="password" name="password" value="" id="password">
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ request.get_full_path }}" />
</form>
# or if it's not declareв шт urls:
<form action="{% url django.contrib.auth.views.login %}?next={{ request.get_full_path }}" method="post">
everything worked fine.
PS: are you absolutely sure that "context_processors.request" is included in settings? Forgetting to include it is a common problem.
UPD: As far as I know, there are no way to make default login view to redirect on failed login (It just doesn't work that way).
Still i may be wrong
Finally I created a login view that calls django.contrib.auth.views.login internally.
I'd suggest to pass a previous url as a parameter within the url:
/accounts/login/?next=my_previous_url
and then use this value in a view
request.next
{{request.get_full_path}} gives you the current path, so is normal that the redirect points to the same place, change it for {{next}} in your registration/login.html template
Adding up to #Sean's anwer. Code for iterating over each form field in order to write field error above the miss-typed field.
So, in Sean's login.html is the existing code:
login.html
<html>
<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
{% csrf_token %}
{{form}}<br/> <!-- I can change! -->
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
</html>
Now what you should do is replace the "I can change!" line (4th line in the above code snippet) with following code:
{% for field in form %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<span class="text-danger small"> {{ field.errors }}</span>
</div>
<label class="control-label col-sm-2">{{ field.label_tag }}</label>
<div class="col-sm-10"> {{ field }}</div>
</div>
{% endfor %}
You can use this snippet for other forms too (for example registration). :)
I stumble upon this question in my process of implementing Facebook Account Linking. The problem is the same: how do I correctly redirect django after successful login?
Remember this: your settings.py contain LOGIN_REDIRECT_URL right? So, that's the only place where you should do the logic of redirecting. To do that, first connect this signal (put this in your views.py):
def after_success_login(sender, user, request, **kwargs):
alt = request.GET.get('account_linking_token')
if alt is not None:
uri = request.GET.get('redirect_uri')
request.session['fb_redirect_uri'] = uri
user_logged_in.connect(after_success_login)
The logic above may not reflect your case, but the idea is setting up a session variable to be read in the route defined as LOGIN_REDIRECT_URL.
So, in my case:
def index(request):
if not request.user.is_authenticated():
form = SignUpForm()
return render(request, 'index.html', {'form': form})
else:
# FB ACCOUNT LINKING!
if 'fb_redirect_uri' in request.session:
redirect_uri = request.session['fb_redirect_uri']
del request.session['fb_redirect_uri']
to = '{}&authorization_code={}'.format(redirect_uri, request.user.username)
print('to', to)
return redirect(to)
That's it!
Add a decorator before the view function should be OK.
#login_required
see here for details