Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manipulate URL fragment on redirect in Django

I have been using Django's auth module but recently had to switch off of it. The auth module handled session expirations by redirecting to the login page and setting the page you were logged out from as the ?next=/currentPage parameter.

So if my session expired on #dashboard I would be redirected to:

mydomain/account/login?next=/#dashboard

After moving off of Django auth module, I noticed this has changed to:

mydomain/account/login/#dashboard

This seems consistent with how I understand it should function after reading URL Fragment and 302 redirects, however, I'd like to manipulate this fragment but don't see it anywhere in my HttpResponse object.

django.contrib.auth uses the following functions to handle this request, but I don't see where they're moving the fragment. Realistically I'd just like to remove the fragment completely, but if I can't I'd settle for having it back in ?next= parameter.

def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
    """
    Decorator for views that checks that the user passes the given test,
    redirecting to the log-in page if necessary. The test should be a callable
    that takes the user object and returns True if the user passes.
    """

    def decorator(view_func):
        @wraps(view_func, assigned=available_attrs(view_func))
        def _wrapped_view(request, *args, **kwargs):
            if test_func(request.user):
                return view_func(request, *args, **kwargs)
            path = request.build_absolute_uri()
            # urlparse chokes on lazy objects in Python 3, force to str
            resolved_login_url = force_str(
                resolve_url(login_url or settings.LOGIN_URL))
            # If the login url is the same scheme and net location then just
            # use the path as the "next" url.
            login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
            current_scheme, current_netloc = urlparse(path)[:2]
            if ((not login_scheme or login_scheme == current_scheme) and
                (not login_netloc or login_netloc == current_netloc)):
                path = request.get_full_path()
            from django.contrib.auth.views import redirect_to_login
            return redirect_to_login(
                path, resolved_login_url, redirect_field_name)
        return _wrapped_view
    return decorator


def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
    """
    Decorator for views that checks that the user is logged in, redirecting
    to the log-in page if necessary.
    """
    actual_decorator = user_passes_test(
        lambda u: u.is_authenticated(),
        login_url=login_url,
        redirect_field_name=redirect_field_name
    )
    if function:
        return actual_decorator(function)
    return actual_decorator
like image 428
diplosaurus Avatar asked Jan 10 '23 18:01

diplosaurus


1 Answers

They're not removing it. Fragments are never sent to the backend: that's just how browsers work.

Note that your original URL is not being interpreted as next="/#dashboard" at all, but next="/", with a subsequent fragment of "dashboard". That is, the fragment is separate to the querystring, not part of it.

What you need to do is to encode the hash, so that it is part of the querystring itself.

mydomain/account/login?next=/%23dashboard
like image 99
Daniel Roseman Avatar answered Jan 18 '23 21:01

Daniel Roseman