Problem
The django.contrib.auth.login function is succeeding, but the session does not seem to persist.
Code
I am creating my own set of functions to use with an AJAX client inside of my Django server.
I have the following code in urls.py:
from django.contrib.auth import authenticate, login
from django.conf.urls import url
from django.http import JsonResponse
import json
def auth_login(request):
username = json.loads(request.body)['username']
password = json.loads(request.body)['password']
user = authenticate(request, username=username, password=password)
if user is not None and user.is_active:
login(request, user)
return JsonResponse({}, status=200)
else:
return JsonResponse({}, status=400)
urlpatterns = [
url(r'auth/login/', auth_login, name='login')
]
Details
As mentioned above, the call to login() succeeds. request.session is being set properly, and I can access if from within auth_login. On subsequent requests, request.session does not exist and django.contrib.auth.get_user returns AnonymousUser.
(Possibly relevant) I am also using the seemingly-popular https://django-tenant-schemas.readthedocs.io/en/latest/. This urls.py file is in an application that is per-tenant, so the user is actually authenticating on tenantname.hostname.com/tenant/auth/login/.
The tenant's django_session table is being set correctly. For each attempted login, I can see session_key, session_data, and expire_data.
The cookie for tenantname.hostname.com is empty after attempted logins.
I'm just out of ideas as to what other things I could try to lead me to a solution.
Question(s)
Any thoughts as to why this session isn't actually saved into the cookie?
OR
Thoughts as to what else I could try that could lead me to a solution?
Related
I need to make a request to b.com/rest/foo to get json data for my application. I want to do it this way to protect the credentials rather than expose them on every page.
I found Consume an API in Django REST, server side, and serve it ,client side, in Angular and the corresponding answer at https://stackoverflow.com/a/65672890/2193381 to be a great starting point.
I created a local url to replicate the data that the external server will return and then tried the following
import requests
from django.http import JsonResponse
from django.contrib.auth.decorators import login_required
from django.views.decorators.cache import never_cache
#never_cache
#login_required
def fakedata(request, item):
return JsonResponse({'item': item})
def getdata(request, item):
url = f"http://localhost:8080/rest/{item}"
username = os.getenv('SITE_USERNAME', None)
password = os.getenv('SITE_PASSWORD', None)
userpass = dict(username=username, password=password)
data = requests.get(
url,
auth=requests.auth.HTTPBasicAuth(**userpass),
)
if data is not None and data.status_code == 200:
try:
return JsonResponse(data.json(), safe=False)
except ValueError:
print("!JSON")
return JsonResponse({})
print("!data")
return JsonResponse({})
urlpatterns = [
path('rest/<str:item>', fakedata),
path('foo/<str:item>', getdata),
]
When I test it with
python manage.py runserver 8080
and call http://localhost:8080/foo/a, I am getting back the html of the login page and not the data from http://localhost:8080/rest/a that I am expecting.
What changes do I need to make to get it to work?
I just went through Django documentation and found this useful and working.
you can first authenticate the user by using the authenticate() method then login with request and call your fakedata() function with passing the request:
from django.contrib.auth import authenticate, login
user = authenticate(request, **userpass)
if user is not None:
login(request, user)
data = fakedata(request, item)
else:
pass
I am using the Django-two-factor-auth library for my sites login. Everything is working fine, however when I try to login and redirect a new user to their profile page after sign up using login(request, user) I keep getting redirected to the login page.
The login works fine when the user re-enters their new login credentials however I want to redirect the user straight to their profile page after signup instead.
I am aware Django-two-factor-auth overides Django's built in authentication (Django.contrib.auth), however I am unsure why the login() function is not marking the user as authenticated.
views.py
from django.contrib.auth import login
def signup(request):
...
user = signup_form.save()
login(request, user)
return redirect('/profile')
You can add that to your settings:
LOGIN_REDIRECT_URL = 'yourUrl' # this is the name of the url
Resolved. Turns out the 'is_active' field of the newly created user was being modified by a model signal elsewhere in my code resulting in the user being redirected to the login page.
I understand that in order to override from django.contrib.auth.views.LoginView one has to use a subclass Class(LoginView) in views.py.
However, in my views.py I only have views declared with def my_view(request)
In old versions of Django I could just do
from django.contrib.auth.views import login, logout
def login_user(request):
result = login(request=request, template_name='Market/pages/login.html')
return result
What's the modern Django equivalent of this? The documentation has this example, that forces me rewrite the whole username/password logic into my view:
from django.contrib.auth import authenticate, login
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
...
else:
# Return an 'invalid login' error message.
...
How can I use a view function (not class!) and still have the automatic managing of the submitted request?
You're missing the point. The reason behind the move to class-based views is that they are more configurable than function-based ones.
In this case, you don't even need to define your own view to get the result you want; you can just do it in the URL:
path('login/', views.LoginView.as_view(template_name='Market/pages/login.html'), name='login')
I am using Django 1.9.
Base on the Django documentation:
" To log a user in, from a view, use login(). It takes an HttpRequest object and a User object. login() saves the user’s ID in the session, using Django’s session framework."
So how do I retrieve the information in that session.
For example: (this is also taken from the documentation)
from django.contrib.auth import authenticate, login
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
**login(request, user)**
# Redirect to a success page.
else:
How do I retrieve the user information such as username or if possible the password out on the success page.
P.S
If you could also kinda explain the solution in layman term as possible
EDIT
I was playing around with the framework back then. So I was testing if it can be done.
You don't get it from the session.
The authentication middleware adds the current user to the request, as request.user.
(And you definitely do not ever retrieve or display the password.)
I am trying to make a application in django. I have an authentication api from another application. I take input from user via form and post the input to the api in json. After I get success message from api and my user is authenticated to api I want to make that user as request.user in django.
Is there any way I can do it. I am thinking of doing it in middleware in process_view. Is this right approach ? But I have no idea how to do it.
Any suggestion will be appriciated.
If you are really doing it thru Django views, you can manually login the user with:
# imports needed
from django.contrib.auth import login, logout
from django.contrib.auth.models import User
# hard way to login a user
user = User.objects.filter(username=INPUT_USERNAME).first()
user.backend = 'django.contrib.auth.backends.ModelBackend'
login(request, user)
If you need to logout:
logout(request)