DJANGO: Dynamically forward to "next" after login with #user_passes_test - django

I'm new to the django login setup.
And I've researched my way to something that seemed good and copied that.
I have discovered this decorator:
#user_passes_test
That helps me make sure people with the right access to my "/dashboard" page have logged in.
After getting redirected to login the url is:
placeholder.it/login/?next=/dashboard/%3Fcvr%3D24256790
BUT the user always get send to:
placeholder.it/accounts/loggedin
insted of the next url.
How come??
This is some of my code:
views.py
#user_passes_test(lambda u:u.is_staff, login_url='/accounts/login/')
def dashboard(request):
cvr = request.GET.get('cvr', '')
return render(request,'dashboard.html', { "cvr": cvr})
def login(request):
c = {}
c.update(csrf(request))
return render_to_response('login.html', c)
def auth_view(request):
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
return HttpResponseRedirect('/accounts/loggedin')
else:
return HttpResponseRedirect('/accounts/invalid')
login.html
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p class="error">Sorry, that's not a valid username or password</p>
{% endif %}
<form action="{% url 'auth' %}" 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" />
</form>
<br>
Login to access all sites
{% endblock %}
urls.py
url(r'^accounts/login/$', views.login, name='login'),
url(r'^accounts/auth/$', views.auth_view, name='auth'),
url(r'^dashboard/$', views.dashboard, name='dashboard'),
Appreciate any help <3

Your decorator is sending the users who are not logged in to the login view. The login page has a form that posts to the auth_view view. The auth view explicitly redirects every logged in user to /accounts/loggedin.
You're redirecting users on your own, through the codes in auth_view. Your code doesn't respect the next query parameter (that the decorator is appending to the login url). Your code should read the value of the next parameter and put it in a hidden field inside the form. On the POST request to auth_view, you should read that value and redirect the user to that url.

There is an inbuilt decorator to handle if user has logged in or not
Import the following
from django.contrib.auth.decorators import login_required
And place the decorator above your function:
#login_required(redirect_field_name='next')
def page(request):
Add this to your login template
input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"

Related

How to set up Login View in Python Django?

I'm trying to set up passkeys to a testing Django website I made a while back following this guide, but at some point I get asked to "In your login view, change the authenticate call to include the request as follows":
user=authenticate(request, username=request.POST["username"],password=request.POST["password"])
However I don't have a Login view as I'm using this in my urls.py:
path("login/", userViews.LoginView.as_view(), name="login"),
I've tried to look up for guides in how to set up a login view manually but they all get me to the simplified version I'm using already.
Is there way to add that line regardless?
Otherwise, how do I create a login view manually and how should I change my login.html file?
Thanks!
Usually, we create a form in forms.py with a username and password then render this form into html template and within our view we can authenticate and then login our user.
HTML template
<body>
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
<form action="" method="post">
{% csrf_token %}
<label for="">username</label>
<input type="text" name="username" id="">
<label for="">Password</label>
<input type="password" name="password" id="">
<input type="submit" value="Login">
</form>
</body>
then handle this form in views.py file by creating loginview for it
def loginview(request):
if request.method == 'POST':
user = authenticate(request, username=request.POST["username"],
password=request.POST["password"])
if user:
login(request, user)
messages.success(request, 'Logged in successfully')
return redirect('home')
else:
messages.error(request, 'Logged in Fail')
return render(request, 'test_app/home.html')
url path
from .views import loginview
urlpatterns = [
path('', loginview, name='login'),
]

Trying to render two different views in one template according to their specific url routing

Im trying to render login and register view in a single template using variable assignment and if-else. I'm sorry if its a rookie mistake, Im pretty new to this..
github repo- https://github.com/varundhand/DevSearch
my urls.py :-
urlpatterns = [
path('login/',views.loginUser,name='login'),
path('logout/',views.logoutUser,name='logout'),
path('register/',views.registerUser,name='register'),
path('',views.profiles,name='profiles'),
path('profile/<str:pk>/',views.userProfile,name='user-profile'),
]
my views.py :-
def loginUser(request):
page = "login"
if request.user.is_authenticated:
return redirect('profiles')
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
try:
user = User.objects.get(username=username)
except:
messages.error(request,'Username doesnt exist')
user = authenticate(request,username=username,password=password)
if user is not None:
login(request,user)
return redirect ('profiles')
else:
messages.error(request,'Username/Password incorrect')
context = {page:'page'}
return render(request, 'users/login_register.html', context)
def logoutUser(request):
logout(request)
messages.error(request,'User was logged out!')
return redirect('login')
def registerUser(request):
page = "register"
context= {page:'page'}
return render(request,'users/login_register.html', context)
my html template file :-
{% extends 'main.html' %}
{% block content %}
{% if page == "register" %}
<h1>Register User</h1>
<p>Already have an account? Login </p>
{% else %}
<form action="{% url 'login' %}" method="POST">
{% csrf_token %}
<input type="text" name="username" placeholder="Username">
<input type="pass`your text`word" name="password" placeholder="Enter Password">
<input type="submit" value="Login">
<p>Dont have an account? Sign Up</p>
</form>
{% endif %}
{% endblock content %}
My Approach
I gave variable assignment of page='login' and page='register' in loginUser and registerUser view respectively and then i gave an if-else in my common template but for some reason only loginUser view is working even when i go to the register url.
Ignore my silly question, I was passing the wrong context dictionary i.e. it shoulda been context = {'page':page}

Django Authentication system modifications

I am new to Django Authentication system and I am unable to find the correct debugging method.
I want to create a function to handle login requests and I have done the necessary steps to do the same.
created a login url path in main project URLS.py file.
path('members/', include('django.contrib.auth.urls')),
path('members/', include('members.urls')),
created a login url in members app to point to a function created in views.py
urlpatterns = [
path('login/', views.login_user, name='login'),]
defined what to do when user comes to specific url
def login_user(request):
if request.method == 'POST':
print('-'*100)
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
messages.success(request, ("You are now logged in"))
return redirect('index')
else:
messages.success(request, ("Invalid credentials"))
return redirect('login')
return render(request, 'registration/Login.html')
I have created a Login Page in templates folder.
{% extends 'Base.html'%}
{% block title %}
Login to the Blog Page
{% endblock %}
{% block content%}
<h1>Members Login</h1>
<div class="form-group">
<form method="POST" action="">
{% csrf_token %}
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">User Name</label>
<input type="text" class="form-control" name = "username">
<div id="emailHelp" class="form-text">We'll never share your email with
anyone else.</div>
</div>
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label">Password</label>
<input type="password" class="form-control" name="password">
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
<br>
</div>
{% endblock %}
Now when I get to the /members/login after submitting the user details the print statement in post method is not printed in the console. So I am suspecting that the post request is not being redirected to the login_user function. Can anyone help me out to identify why?
Djnago will fire the view that it first finds for the path members/login, and that is the login view of the django.contrib.auth module. You can swap the order of the views to visit the login view of your view:
urlpatterns = [
path('members/', include('members.urls')), # 🖘 `members.urls first
path('members/', include('django.contrib.auth.urls'))
]
But it might be better to give your view a different path, to prevent any confusion.

Should I use action in the login form templated?

I want to know that if I am using the action in login.html <form > tag and if not using it, In both cases all is good. I am able to successfully login and if there is any error, my views.py showing the respective errors.
I think after rendering the template the django automatically send the data back to user_login function in views.py without specifying the action attribute to the <form > tag.
I just want to know that when do I need to use action attribute in the <form > tag in django template.
My urls.py
from django.urls import path
from . import views
# TEMPLATE URLS!
app_name = 'basic_app'
urlpatterns = [
path('register/', views.register, name='register'),
path('user_login/', views.user_login, name='user_login'),
]
views.py
def user_login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user:
if user.is_active:
login(request, user)
return HttpResponseRedirect(reverse('index'))
else:
return HttpResponseRedirect("ACCOUNTS NOT ACTIVE")
else:
print("Someone tried to login and failed!")
print("Username: {} and password: {}".format(username, password))
return HttpResponse("Invalid login details supplied!")
else:
return render(request, 'basic_app/login.html', {})
login.html
{% extends 'basic_app/base.html' %}
{% block body_block %}
<div class="jumbotron">
<h1>Please Login!</h1>
<form method="post" action="{% url 'basic_app:user_login' %}">
{% csrf_token %}
<label for="username">Username:</label>
<input type="text" id="username" name="username" placeholder="Enter Username">
<label for="password">Password:</label>
<input type="password" id="password" name="password" placeholder="*******">
<input type="submit" name="" value="Login">
</form>
</div>
{% endblock %}
{#action="{% url 'basic_app:user_login' %}"#}
If I am not using action="{% url 'basic_app:user_login' %}" in <form > tag of login.html, nothing changes.
#Aditya Gupta
Please look this answer first ---->>>
Now in django normaly you must define action attribut when you want the view you specified on it receive some data. It recommanded to specify url of in action attribute of form.

django-registration-redux custom user model login only working via /admin/

I am using a custom user model for my Django project and I can log in via /admin/ perfectly fine. But when I go to /accounts/login and try to log in, it just bounces me back to the login page without logging in. I am using django-registration-redux with the simple backend.
Via logging I discovered that the error happens in this method in django.contrib.auth.__init__.py:
def get_user(request):
"""
Returns the user model instance associated with the given request session.
If no user is retrieved an instance of `AnonymousUser` is returned.
"""
from .models import AnonymousUser
user = None
try:
#
# EXCEPTION THROWN ON BELOW LINE
#
user_id = _get_user_session_key(request)
backend_path = request.session[BACKEND_SESSION_KEY]
except KeyError:
pass
else:
if backend_path in settings.AUTHENTICATION_BACKENDS:
backend = load_backend(backend_path)
user = backend.get_user(user_id)
# Verify the session
if hasattr(user, 'get_session_auth_hash'):
session_hash = request.session.get(HASH_SESSION_KEY)
session_hash_verified = session_hash and constant_time_compare(
session_hash,
user.get_session_auth_hash()
)
if not session_hash_verified:
request.session.flush()
user = None
return user or AnonymousUser()
Any ideas? /accounts/register/ performs as expected, although I have overridden RegistrationView. Perhaps I have to do the same thing for logging in?
Login.html
{% extends "base.html" %}
{% load staticfiles %}
{% block body_block %}
<link href="{% static 'css/signin.css' %}" rel="stylesheet">
<div class="container">
<div class="jumbotron">
<h1 class="display-3" align="center">Login</h1>
</div>
<form method="post" action=".">
{% csrf_token %}
<h2 class="form-signin-heading">Please sign in</h2>
<label for="inputEmail" class="sr-only">Username</label>
<input type="text" name="email" id="id+username" class="form-control" placeholder="Username" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" name="password" id="id_password" class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit" value="Submit">Login</button>
</form>
Not a member?
Register
</div>
<p>
</p>
{% endblock %}
Urls.py
class MyRegistrationView(RegistrationView):
success_url = '/'
form_class = UserProfileRegistrationForm
def get(self, request, *args, **kwargs):
form = self.form_class(initial=self.initial)
return render(request, self.template_name, {'form': form})
def register(self, form):
logging.debug("THIS IS MY REGISTER")
new_user = form.save(commit=False)
new_user.set_password(form.cleaned_data['password1'])
new_user.save()
login(self.request, new_user)
logging.debug("Logged in")
signals.user_registered.send(sender=self.__class__,
user=new_user,
request=self.request)
logging.debug("After signals")
return new_user
urlpatterns = [
url(r'^', include('base.urls')),
url(r'^admin/', admin.site.urls),
url(r'^accounts/register/$', MyRegistrationView.as_view(), name="registration_register"),
url(r'^accounts/password/change/$', MyRegistrationView.as_view(), name="auth_password_change"),
url(r'^accounts/password/change/done/$', MyRegistrationView.as_view(), name="auth_password_changed"),
url(r'^accounts/', include('registration.backends.simple.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
EDIT:
I have a temporary fix of throwing a view into login in urls.py. Something tells me this is extremely dirty but it seems to work... for now. I'm open to better alternatives.
url(r'^accounts/login/$', my_view, name="login"),
def my_view(request):
if request.POST:
username = request.POST['email']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return render(request, 'index.html', {})
# Redirect to a success page.
else:
# Return an 'invalid login' error message.
pass
else:
return render(request, 'registration/login.html', {})
Try using {{ form }} in your login template, instead of rendering the fields manually. This can show whether the problem is in your template or elsewhere.
In this case, I think that the form fields should be username and password, not email and password as you have.
<input type="text" name="username" id="id_username" class="form-control" placeholder="Username" required autofocus>
<input type="password" name="password" id="id_password" class="form-control" placeholder="Password" required>