Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HttpResponseRedirect after login form not redirecting to profile

Tags:

django

I'm trying to get a local copy of a Django site working. The production site works just fine on login, but my local instance doesn't redirect to the profile page after completing the login form.

This is the login_page view:

def login_page(request):
  profile_page = HttpResponseRedirect('profile')
  if request.user.is_authenticated():
    return profile_page
  form = LoginForm(request.POST or None)
  if request.POST and form.is_valid():
    user = form.login(request)

    if user:
      login(request, user)
      return profile_page

  return render(request, 'login.html', {'form': form})

This is what the debug output of the server shows:

Performing system checks...

<function home_page at 0x7f77ad696c08>
System check identified no issues (0 silenced).
July 08, 2017 - 03:21:39
Django version 1.9.1, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[08/Jul/2017 03:21:49] "GET / HTTP/1.1" 200 3276
[08/Jul/2017 03:21:50] "GET /login HTTP/1.1" 200 2370
[08/Jul/2017 03:21:57] "POST /login HTTP/1.1" 302 0
[08/Jul/2017 03:21:57] "GET /profile HTTP/1.1" 302 0
[08/Jul/2017 03:21:57] "GET /login?next=/profile HTTP/1.1" 200 2370

After the above, the browser is left at http://127.0.0.1:8000/login?next=/profile and just displays the standard login page.

Again, identical code is working on the same version of Django in production (though running through gunicorn/nginx instead of django-admin runserver), so it makes me think that there's something in my Django config that I'm missing rather than an actual code problem.

urls.py entries:

from accounts import urls as account_urls
...
  url(r'^', include(account_urls)),

accounts/urls.py:

from django.conf.urls import url

import accounts.views

urlpatterns = [
  url(r'profile/?$', accounts.views.user_profile_page,
      name='user_profile_page'),

Profile view (this never gets triggered AFICT - sticking a breakpoint in there doesn't help):

@login_required
def user_profile_page(request):
    """Returns user home page, with respective user status of surveys."""

    print "User profile accessed: %s" % request

    // user specific data here

    context = {'some': some, 'data': data,
               'here': here, }
    return render(request, 'accounts/profile.html', context)

Also interesting: resolve_url doesn't seem to do the remapping like I would expect:

(Pdb) resolve_url('/profile')
'/profile'

Shouldn't that point to acccounts/profile or 127.0.0.1:8000/profile or something like that?

This is the AUTHENTICATION_BACKEND's 'authenticate' method that is getting executed (not sure how this differs from standard Django). All of the answers here imply that authenticate needs to accept the request argument - can I update this method to append something here?:

def authenticate(self, username=None, password=None, **kwargs):
    UserModel = get_user_model()
    if username is None:
        username = kwargs.get(UserModel.USERNAME_FIELD)
    try:
      if username is not None:
        username = username.lower()

      user = UserModel._default_manager.get_by_natural_key(username)
      if user.check_password(password):
        return user
    except UserModel.DoesNotExist:
        # Run the default password hasher once to reduce the timing
        # difference between an existing and a non-existing user (#20760).
        UserModel().set_password(password)
like image 695
javanix Avatar asked Jul 08 '17 03:07

javanix


5 Answers

try this

from django.shorcuts import redirect
from django.contrib.auth import authenticate
def login_page(request):
  profile_page = HttpResponseRedirect('profile')
  if request.user.is_authenticated():
    return profile_page
  form = LoginForm(request.POST or None)
  if request.POST and form.is_valid():
    user = authenticate(request,username=form.cleaned_data['username'],password=form.cleaned_data['password'])

    if user:
      login(request, user)
      return redirect('profile')
like image 103
Exprator Avatar answered Nov 10 '22 18:11

Exprator


Instead of HttpResponseRedirect which triggers a HTTP 302, use a HttpResponseTemporaryRedirect to trigger a HTTP 307.

What happens is that 302 does not ensure the replay of the POST request. The reason is as follows:

RFC 1945 and RFC 2068 specify that the client is not allowed to change the method on the redirected request. However, most existing user agent implementations treat 302 as if it were a 303 response, performing a GET on the Location field-value regardless of the original request method. The status codes 303 and 307 have been added for servers that wish to make unambiguously clear which kind of reaction is expected of the client.

What's the difference between a 302 and a 307 redirect?

like image 25
Fabien Avatar answered Sep 22 '22 04:09

Fabien


Changed in Django 1.10:
In older versions, when you’re manually logging a user in, you must successfully authenticate the user with authenticate() before you call login(). Now you can set the backend using the new backend argument.

If you using Django<=1.10, you must use authenticate method before you login. Otherwise, you have to feed authentication backend at least in login method. Here is the code snippet from django docs.

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.
    ...
like image 7
Erdenezul Avatar answered Nov 10 '22 16:11

Erdenezul


Try modifying:

  profile_page = HttpResponseRedirect('profile')

to:

  profile_page = HttpResponseRedirect(reverse('profile'))
like image 2
yusuf.oguntola Avatar answered Nov 10 '22 18:11

yusuf.oguntola


try with class bassed views

class Login(FormView, View):

    template_name = 'login/login.html'
    form_class = AuthenticationForm
    success_url = reverse_lazy("your_succes:url")

    def dispatch(self, request, *args, **kwargs):

        if request.user.is_authenticated():
            return HttpResponseRedirect(self.get_success_url())
        else:
            return super(Login, self).dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        login(self.request, form.get_user())
        return super(Login, self).form_valid(form)
like image 1
Mauricio Cortazar Avatar answered Nov 10 '22 18:11

Mauricio Cortazar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!