Propagating next parameter in login in oauth2app - django

I have a Django Web site where I'm using the oauth2app library for OAuth 2 authentication. I've also modified oauth2app to use crispy_forms, instead of the deprecated uni_form.
The authorize() method in oauth2app is guarded by a Django decorator, #login_required. Indeed, if a client tries to authorize without first logging in, the login page appears.
As expected, the decorator causes the login page URL to have a "next" CGI parameter with the original URL for the authorization request.
The problem is, the "next" parameter is not propagated when the template for the login page is instantiated. What I'd like is for the form "action" to contain the "next" parameter.
This page purports to offer a solution:
http://django-uni-form.readthedocs.org/en/latest/helpers.html
in the section "Manipulating a helper in a view".
Following that example, I tried:
form = LoginForm()
redirect_url = request.GET.get('next')
if redirect_url is not None:
form.helper.form_action = reverse(login) + '?next=' +
redirect_url
But the source for the resulting page shows the original "action" for the form. The assignment to the form_action appears not to take effect. Indeed, if I don't instantiate the template, but just return the form_action, it hasn't changed:
return HttpResponse('action: ' + form.helper.form_action)
Color me puzzled.

The author of uni_forms clued me in here.
The problem is that the form helper was a property, so that the form_action was a fixed piece of that property.
By changing the property to a method that creates the helper, the form_action can be dynamically modified.
Everything works now, no Javascript hacks needed.

Related

Back button on Django

I am trying to use HTTP_REFERER to create a link to the previous page. However, let's say I have a 'page1' that calls the 'page2' get method. It will show a form at the 'page2' where I can do a post request. When I post on the 'page2', the HTTP_REFERER is referencing the same page (page2), therefore I can't to back to the 'page1'. Is there anything I can do to go back to the 'page1'?
You will need to add a hidden next field to your form . This will capture the previous page by making use of the HTTP_REFERER. After your post request you can then perform a redirect to the page you were on before the form page.
Edit:
More information can also be found here.

LOGIN_REDIRECT_URL in django

I am very new to Django and I'm nearing the end of the django girls tutorial. I have added "#login_required" above my post_detail in views (view for clicking on a specific post) and added a login.html template. So when I click on a post title I get redirected to my login page (so far, so good) and the url is: http://127.0.0.1:8000/accounts/login/?next=/post/11/ (trying this on my computer atm.)
Then I type in my admin name/password and automatically get redirected to http://127.0.0.1:8000/accounts/profile/ and of course get a "Page not found (404)" (since I have no url/view/template for that). I thought "Dang, I just wanted to be redirected to /post/11/"!
Looked around on stack overflow and found this question:
Signing in leads to "/accounts/profile/" in Django (sounds about right)
and got the answer
Change the value of LOGIN_REDIRECT_URL in your settings.py.
So I looked up LOGIN_REDIRECT_URL in the Django documentation:
Default: '/accounts/profile/'
The URL where requests are redirected after login when the contrib.auth.login view gets no next parameter.
This is used by the login_required() decorator, for example.
This setting also accepts named URL patterns which can be used to reduce configuration duplication since you don’t have to define the URL in two places (settings and URLconf).
Deprecated since version 1.8: The setting may also be a dotted Python path to a view function. Support for this will be removed in Django 1.10.
But doesn't my contrib.auth.login get a next parameter? (looking at my url that say "?next=/post/11/" at the end) Please help me out here, I'm lost for what the problem could be here :(
You can view the page at:
http://finbel.pythonanywhere.com/
And the source code at:
https://github.com/Finbel/my-first-blog
UPDATE (1):
So I now know that the LOGIN_REDIRECT_URL is the thing that's deciding where I end up next, which must mean that it ignores the next-parameter in the url. I googled further on the problem and found this question which was very similar to my problem, i.e.
Documentation states that I need to use the "next" parameter and context processors. I have the {{next}} in my template, but I'm confused on how to actually pass the "/gallery/(username)". Any help would be greatly appreciated.
(I don't even have the {{next}} in my template, where/how should I add it?)
The preferred answer to that question seemed to be:
Django's login view django.contrib.auth.views.login accepts a dictionary named extra_context. The values in the dictionary are directly passed to the template. So you can use that to set the next parameter. Once that is done, you can set a hidden field with name next and value {{ next }} so that it gets rendered in the template.
But I'm not sure how to interpret this. While writing this edit I got an answer on this post (by kacperd) and will read it through now)
The problem is that contrib.auth.login doesn't get the next parameter.
When you try to get the login_required view without credentials your request is redirect to login view, and the template you created is rendered. The next parameter is present in this view, but when you perform the login action which is submitting the form, you are not including next in your request so contrib.auth.login doesn't get it and redirects to default page.
The solution to your problem is to include the next param and pass it forward. You can do this by modifying your login template. Simply add ?next={{ request.GET.next }} to form action attribute.
<form method="post" action="{% url 'django.contrib.auth.views.login' %}?next={{ request.GET.next }}">

retrieving action attrubute of form in django view

In my proxy app, I want to retrieve the action of submitted form but I can't find any attribute in request object passed to the view.
I tried request.path but it's incomplete. for example if true action of form was /proxy/?url=http://www.farsnews.com, the value of request.path is /proxy/ that is obviously useless.
I searched the other attributes of request object but didn't help.
The querystring parameters, which are also known as GET parameters, are available via request.GET. This is fully covered in the documentation for the request object.

To stop a redirect back to logout when the login URL ends with ?next=/accounts/logout/ in Django

In my template I am currently using the next parameter to redirect the user back to the page before the login page with this:
Log in
The firstof tag makes sure that in case request.path is invalid, then it will redirect back to the root URL.
This works well on every page except one: the logout page. If I wanted to switch user, then I would first log out, then click log in. But then my url would be
http://127.0.0.1:8000/accounts/login/?next=/accounts/logout/
So as soon as I log in, I would immediately be logged back out again. How do I modify the template so with something like this pseudocode:
if request.path and request.path != reverse( 'auth_logout' )
return request.path
return "/"
The easiest solution I can think of, is add "?next=/" to your logout url, that way, as soon as the user logs out, he will be immediately redirected to the specified url, so no one will ever stay on logout page upon logout.
Otherwise you would have to rewrite the login view and add any custom logic you need, which would be easier if contrib.auth views were class views, which they are currently not unfortunately.
So copy paste it and modify :) (I know that copy pasting is bad, but thats the only way you could add custom behavior to it).
The view is located here:
https://code.djangoproject.com/browser/django/trunk/django/contrib/auth/views.py#L25

How to redirect to page which has GET parameters after login using the {{next}} variable in django

I am using allauth to provide registration and login in my django site. Everything else seems to be working fine other than that I am having problems to redirect the person to the current page after login.
I have a page where I have some interview questions and a typical url for it would be like
/questions/?company=google
This page contains a list of questions for the company google, but to view the answer the person needs to login. The answers are displayed in a dropdown box. However when the user clicks on login a request is sent to the login page as follows
/login/?next=/questions/
And the get parameter which was actually there in my actual page is not sent because of the & in my url. How can I solve this problem. It does not look nice that the person is redirected to a different page from where he/she tried to login.
I know sending the next parameter as a GET variable is not the solution, but is there a way I can send the redirect link as a POST variable from the template.
I tried another thing, in my view that displays the questions list. I set session variables which contains the url of the current link . If a user clicks on login, in my login view I check for this particular session variable. If it is set then I redirect to that page.
However the session variable is not received in the login view, I am not sure but I think the session is reset when the user goes to the login view.
Any suggestions are appreciated.
Have you tried
next = request.get_full_path()
This will return correct path with all queries ( see docs ) , you can then pass it as GET param to redirect url e.g.
full_path = request.get_full_path()
return HttpResponseRedirect('%s?next=%s' % (reverse('login'), full_path))
You should encode the URL-parameter in this case. You want to send a variable like /questions/?company=google, but as you mentioned the ?, = (amongst others) characters are special ones. It has a special meaning when embedded in the URL. If you encode the variable with URL encoding, it becomes %2Fquestions%2F%3Fcompany%3Dgoogle. If you assign that to the parameter next, the URL becomes: /login/?next=%2Fquestions%2F%3Fcompany%3Dgoogle. This should redirect to the correct place on login.