I have the following setup:
Apache Webserver running a Django Frontend Webpage
Application Server running a Django REST Framework
I now have to integrate the the Django Frontend into a 3rd party project which is written in java and angular. The authentication is completely handled by this 3rd party.
Users login over LDAP and create a JWT token.
Is it possible to simply receive the token in Django and authenticate the User after successfully decoding the token? And how would this work with the #login_required decorator when I have protected functions?
Is there some sort of project where I can orient on, or do I have to write all myself?
I use a built-in User model to store usernames. This enables me to login the user when authentication is successful and then use Django functionalities such as #login_requested as you'd normally use them.
Below is a sample code (without the code for REST authentication).
from django.contrib import messages
from django.contrib.auth import login
from django.contrib.auth.models import User
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from django.views.decorators.cache import never_cache
#never_cache
def user_login(request):
''' User login '''
if request.user.is_authenticated:
return HttpResponseRedirect(reverse('main:index'))
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# Your code for authentication here
# authenticate = ....
if authenticate:
# Get user // create one if it doesn't exist yet
user, created = User.objects.get_or_create(username=username)
# Login user - #login_required decorator can be used after user has been logged in
login(request, user)
next = request.POST.get('next', '/') if request.POST.get('next') else '/'
return HttpResponseRedirect(next)
else:
messages.warning(request, 'Authentication failed', extra_tags=forgot_password)
return HttpResponseRedirect(reverse('main:login'))
else:
return render(request, 'main/login.html', {})
Related
My Django app has an option for login/register using CustomForm (inherited from the UserCreationForm) as well as Outh. Now the problem is if a user has already signed up using the CustomForm and if the next time he tries to log in using google Oauth then instead of logging in, google Oauth is redirecting to some other signup form (not created by me) which looks like:
But as the user is already registered, if he enters the same username/email here then it displays says username taken. So how can I resolve this issue? I mean I want the user to be able to login using Oauth even if he has signed up using the CustomForm, how can I implement that? Or even if I ask the user to fill this form to be able to use OAuth login, the problem is that his email/username are already present in the db, so he won't be able to sign up using this form.
Edit:
If that's difficult to implement then instead how can I just show a message when the user tries to login using oauth after signing up with the CustomForm, something like "You signed up using username rather than google account", rather than taking him to the socialaccount signup form?
My register function in views.py:
def register(request):
if request.method == 'POST':
form = CustomForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('login')
else:
return redirect('register')
else:
return render(request, 'accounts/register.html')
forms.py looks something like this:
class CustomForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ("username", "email")
You can use pre_social_login signal
from allauth.exceptions import ImmediateHttpResponse
from allauth.socialaccount.signals import pre_social_login
from allauth.account.utils import perform_login
from allauth.utils import get_user_model
from django.dispatch import receiver
from django.shortcuts import redirect
from django.conf import settings
#receiver(pre_social_login)
def link_to_local_user(sender, request, sociallogin, **kwargs):
email_address = sociallogin.account.extra_data['email']
User = get_user_model()
users = User.objects.filter(email=email_address)
if users:
perform_login(request, users[0], email_verification=settings.EMAIL_VERIFICATION)
raise ImmediateHttpResponse(redirect(settings.LOGIN_REDIRECT_URL))
See https://github.com/pennersr/django-allauth/issues/215
I have a basic login, sign up html page in my Django project: the login page redirects to the user_login function in views.py as follows:
<form action="{% url 'user_login' %}" method="POST">. //rest of the code
In urls.py the request is getting forwaded correctly:
.......#beginnning code
path('user_login', views.user_login, name='user_login'),
path('portfolio', views.portfolio, name='portfolio'),
......
In views.py this is my user_login code to authenticate the user and redirect the user to a 'portfolio.html' page if the user credentials are correct.
I have imported User, Login class as follows:
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .models import Profile
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login
# Create your views here.
def index(request):
return render(request, 'mysite/index.html')
def user_login(request):
if request.method == 'POST':
name_r = request.POST.get('name')
password_r = request.POST.get('password')
user = authenticate(username=name_r, password=password_r)
if user:
login(request, user)
#below line might be incorrect
return HttpResponseRedirect('mysite/portfolio.html')
else:
return render(request, 'mysite/login.html')
#rest of the code for signup which is working perfectly.
Whenever i click on Login page, the login page never loads in the first place, let alone checking whether authentication is taking place or not.
The error occurring is as follows:
I am not sure exactly where the error is occurring and what solution must be applied to it.
Your view never returns anything if request.method is not POST.
django-rest-framework makes use of django.contrib.auth for authentication and authorization (as stated in the django-rest-framework authentication api guide)
However, no-where in the documentation does it talk about how users are actually authenticated using the rest-framework
By default the django.contrib.auth views will respond with a server-side rendered login form.
However, if using a client-side framework such as AngularJs this is not desired - you simply want an api endpoint against which you can authenticate.
Questions:
Is there django-rest-framework documentation I am somehow missing which explains how user authentication is done-out-of-the-box?
Does an out-of-the-box solution even exist?
If not, what is the recommended way of achieving this with minimal reinvention of the wheel?
lets say that you have login view:
Note: with this method you have to assure SSL/TLS because username and password are sending as plain text.
import json
import requests
def login(request):
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
login_url = 'http://your_url:port/rest-api/login/'
response = requests.post(login_url, data={'username': username, 'password': password})
response = json.loads(response.text)
if response.status_code == 200:
return render_to_response("login.html", {"success": True}, RequestContext(request))
your view in rest-api:
from django.contrib.auth.backends import ModelBackend as DjangoModelBackend
def login(request):
response = base_response.copy()
username = request.DATA.get('username', '')
password = request.DATA.get('password', '')
user = DjangoModelBackend().authenticate(username=email, password=password)
if user is not None:
response["message"] = "Authenticated"
else:
response["message"] = "Login Failed"
return Response(response)
and here is the part of ModelBackend
from django.contrib.auth import get_user_model
class ModelBackend(object):
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel._default_manager.get_by_natural_key(username)
if user.check_password(password):
return user
except UserModel.DoesNotExist:
return None
You don't usually go through login forms when authenticating yourself at an API endpoint - you either use an API token or send the authentication credentials through a header, see How to use Basic Auth with jQuery and AJAX? on how to do that.
I tried the following to specific different signup flows for users who sign up via social accounts (facebook) and those that sign up via traditional login.
from django.conf import settings
from allauth.account.adapter import DefaultAccountAdapter
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
class NormalAdapter(DefaultSocialAccountAdapter):
def get_login_redirect_url(self, request):
if request.user.last_login == request.user.date_joined:
return 'survey/'
else:
return '/results/'
class CorporateAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
if request.user.last_login == request.user.date_joined:
return 'corporate/survey/'
else:
return 'corporate/results/'
But even if you log in with facebook, it calls DefaultAccountAdapter's get_login_redirect_url instead of DefaultSocialAccountAdapter's.
Point the all auth plugin to the correct adapter classes! Add the following settings to your django app:
# project/settings.py:
ACCOUNT_ADAPTER = 'python.path.to.your.CorporateAdapter'
SOCIALACCOUNT_ADAPTER ='python.path.to.your.NormalAdapter'
Then save and reload the app (if you are on apache, just restart apache)
i have my login form in the homepage itself i.e. "/". now from there i want to redirect a user to 0.0.0.0:8000/username where 'username' is not static, it i different for different users.
I'm a beginner to Django. Pls explain in dept. Thanks in advance
what you could do is define a home url and a profile url in your urls.py like this.
#urls.py
url(r'^$', 'app.views.home'),
url(r'^(?P<username>\w+)/$', 'app.views.profile'),
now under views.py define 2 views one to render the home page and second to render the profile page
# views.py
import models
from django.shortcuts import render_to_response
from django.templates import RequestContext
from django.contrib.auth import authenticate, login
def home(request):
"""
this is the landing page for your application.
"""
if request.method == 'POST':
username, password = request.POST['username'], request.POST['password']
user = authenticate(username=username, password=password)
if not user is None:
login(request, user)
# send a successful login message here
else:
# Send an Invalid Username or password message here
if request.user.is_authenticated():
# Redirect to profile page
redirect('/%s/' % request.user.username)
else:
# Show the homepage with login form
return render_to_response('home.html', context_instance=RequestContext(request))
def profile(request, username):
"""
This view renders a user's profile
"""
user = user.objects.get(username=username)
render_to_response('profile.html', { 'user' : user})
Now when the first url / is requested it forwards the request to app.views.home which means the home view ===within===> views.py ===within===> app application.
the home view checks if a user is authenticated or not. if a user is authenticated it calls the url /username otherwise it simply renders a template called home.html in your templates directory.
The profile view accepts 2 arguments, 1. request and 2. username. Now, when the profile view is called with the above mentioned arguments it gets the user instance for the username provided and stores it in a user variable and later passes it to the profile.html template.
also please do read through the very easy Poll Application Tutorial on Django Project to get familiar with the power of django.
:)