CSRF token passing breaks my django view - python

When passing the X-CSRFToken header or sending csrfmiddlewaretoken in the POST data to my view, it completely skips the ajax handler and goes directly to the index/base view.
Javascript:
$.post("/action/register", {
name: $('#input_name').val(),
email: $('#input_email').val(),
csrfmiddlewaretoken: '{{ csrf_token }}'
}, function(data) {
var response;
try {
response = JSON.parse(data.toString());
} catch(e) {
response = {"status":"error", "message":"Please try again later, we're having some tech issues!"};
}
// ... process some stuff, the callback works which is good
View:
def handle_register(req):
''' Request handler pyfor registration, should return JSON for the AJAX request. '''
if req.is_ajax():
return validate_and_register(req)
else:
return HttpResponse('{"status":"error","message":"Invalid request."}')
urls.py:
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^action/register$', 'views.handle_register', name='handle_register'),
url(r'^admin/', include(admin.site.urls)),
url(r'^.*$', 'views.handle_home', name='handle_home'),
)
When I don't pass the header, i get a 403 (CSRF_VERIFICATION_FAILED). When I pass the appropriate header (confirmed in multiple browsers) it skips the /action/register handler and goes directly to the "handle_home" view.
I'm stuck!

This could possible be due to a missing slash on your url
/action/register
Try adding a slash in url and in your javascript.
Another guess would be:
'views.handle_register'
is missing an app name?
A more safe was as well would be to use reverse urls:
from django.core.urlresolvers import reverse
url = reverse('appname.views.handle_register')
$.post(url, {}, func...

This was an issue with nginx. Per the django/nginx setup docs I found I was missing this in my nginx config:
fastcgi_split_path_info ^()(.*)$;

Related

Django request in html

I have set up django to work in my local environment. I have a python function which takes two parameters and returns data in JSON format. This is set up in my views.py and urls.py as follows:
views.py :
from django.http import Http404, HttpResponse
from X import calculate
def calculate_X(request, para1, text):
#para1 is ignored on purpose
return HttpResponse(calculate(text))
urls.py :
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^calculate-X/(\d+)/([a-zA-Z0-9_ ]*$)',calculate_X),
url(r'^$', TemplateView.as_view(template_name='base.html')),
]
urlpatterns += staticfiles_urlpatterns()
In the base.html file I have a single button which should make the request to the calculate-x url as follows /calculate-X/1/stringdataexample
which would then create an alert() with the contents of the httpresponse ( JSON )
How can I make this request?
(There is another question asked here on SO however it uses request processors which do not relate to my question)
one way could be to trigger an ajax call when you click that button, and then process the response as you wish.
The button's html could be something like this:
<button onclick="processCalculation()">Calculate!</button>
Something like this function:
function processCalculation(){
var para1 = $("#params-container").val();
var text = $("#text-container").val();
$.ajax({
url: "/calculate-X/" + para1 + "/" + text,
data: {}
}).done(function (jsonResponse) {
alert(jsonResponse)
});
}
I hope this points you on the right direction, Best regards!

How to set Paypal redirect url in django oscar?

I got error while redirecting to local server through https request... i did't find any redirect paypal url settings to change the redirecting url to use http method .. how can i set paypal redircting url manually ?
a terminal error like this
"You're accessing the development server over HTTPS, but it only supports HTTP."
This can be done by subclassing the original express RedirectView class and adding in your custom logic:
views.py
from paypal.express.views import RedirectView as OscarPaypalRedirectView
class RedirectView(OscarPaypalRedirectView):
def _get_redirect_url(self, basket, **kwargs):
return my_url
def _get_paypal_params(self):
""" Send extra paypal params """
return {
'SOLUTIONTYPE': 'Mark',
'LANDINGPAGE': 'Login',
'BRANDNAME': 'My Store',
}
And then you can call this class in in your urls:
from .views import RedirectView,
urls = [
....
....
url(r'paypal/redirect/', RedirectView.as_view(), name='paypal-redirect')
]

How to recognise urls starting with anchor(#) in urls.py file in django?

I have starting building my application in angularJS and django, and after creating a login page, I am trying to redirect my application to a new url after successful login. I am using $location variable to redirect my page. Here is my code:
$scope.login = function() {
$http({
method: 'POST',
data: {
username: $scope.username,
password: $scope.password
},
url: '/pos/login_authentication/'
}).then(function successCallback(response) {
user = response.data
console.log(response.data)
if (user.is_active) {
$location.url("dashboard")
}
}, function errorCallback(response) {
console.log('errorCallback')
});
}
My initial url was http://localhost:8000/pos/, and after hitting the log in button, the above function calls, and I am redirected to http://localhost:8000/pos/#/dashboard. But I am unable to catch this url in my regex pattern in urls.py file:
My project urls.py file:
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^pos/', include('pos.urls')),
url(r'^admin/', admin.site.urls),
]
And my pos application's urls.py file:
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^login_authentication/$', views.login_authentication, name='login_authentication'),
url(r'^#/dashboard/$', views.dashboard, name='dashboard')
]
Using this, I am getting the same login page on visiting this http://localhost:8000/pos/#/dashboard link. This means that in my urls.py file of my pos application, it is mapping my http://localhost:8000/pos/#/dashboard to first object of urlpatterns:url(r'^$', views.index, name='index'). How do I make python differentiate between both the links?
You have some major misunderstanding about and anchor in url. The anchor is called officially Fragment identifier, it's not part of the main url, so if you have # when you visit an url like http://localhost:8000/pos/#/dashboard, your browser would treat the remaining #/dashboard as the anchor in page that http://localhost:8000/pos/ renders. You shouldn't be even using it in your urls.py definition. Please read the link above more carefully about the usage of an anchor.
Using help from this answer, I figured a good redirection method through angular which doesn't append any anchor tag using $window:
$scope.login = function() {
$http({
method: 'POST',
data: {
username: $scope.username,
password: $scope.password
},
url: '/pos/login_authentication/'
}).then(function successCallback(response) {
user = response.data
console.log(response.data)
if (user.is_active) {
$window.location.href = '/pos/dashboard';
}
}, function errorCallback(response) {
console.log('errorCallback')
});
}

NoReverseMatch at /rest-auth/password/reset/

I have a django application with an angular front-end. When from the front-end I try to send a request for passwordReset, I get the following error:
Reverse for 'password_reset_confirm' with arguments '()' and keyword
arguments '{u'uidb64': 'MTE', u'token': u'3z4-eadc7ab3866d7d9436cb'}'
not found. 0 pattern(s) tried: []
Its a POST request going to http://127.0.0.1:8080/rest-auth/password/reset/
Following is what my urls.py looks like:
from django.conf.urls import patterns, include, url
from django.contrib import admin
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^rest-auth/', include('rest_auth.urls')),
url(r'^rest-auth/registration/', include('rest_auth.registration.urls')),
url(r'^account/', include('allauth.urls'))
)
I also was having this problem, and found this github issue it said we need to add
url(r'^', include('django.contrib.auth.urls')),
on the urlpatterns.
As stated there it says that The PasswordReset view depends on django.contrib.auth.views.password_reset_confirm view.
As Roar Skullestad pointed out, the problem is with the default email template, which tries to resolve URL by reversing viewname "password_reset_confirm", which is undefined.
It is enough to register a viewname "password_reset_confirm" with a custom route and then default email template rendering will work fine.
You can register viewname with custom route by adding a path to urls.py:
urlpatterns = [
...,
path('password-reset/<uidb64>/<token>/', empty_view, name='password_reset_confirm'),
]
password-reset - custom route that password reset confirmation view. If you have SPA (Angular) - it will be the URL of your SPA view (such as the route to Angular component) that will handle the password reset.
This is the URL that will be resolved and embedded in the email. For this example it will be something like:
http://my-spa.com/app-name/password-reset/Nw/51v-490d4b372ec930e49049/
empty_view - in case of SPA (Angular), you don't really need server-side implementation, because the front end will actually handle this route. I used this implementation of a view, but it can be anything else:
from django.http import HttpResponse
def empty_view(request):
return HttpResponse('')
And since I'm using Angular, this is the route for my Angular component:
{
path: 'password-reset/:uid/:token',
component: PasswordRecoveryComponent
}
For me the problem was this line in site-packages/django/contrib/admin/templates/registration/password_reset_email.html:
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
From what I understand the problem is caused by reverse lookup not working for this line in contrib/auth/urls.py:
url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
'django.contrib.auth.views.password_reset_confirm',
name='password_reset_confirm'),
My (at least temporarily) solution was to override the template and hardcode the reverse lookup part of the url for the link in the email.
The path to the new template is specified in settings.py:
TEMPLATE_DIRS =(
"/absolute/path/to/my/templates/directory",
)
Since I am using angular front end, I also changed the link so that it triggers password reset confirmation via the angular client:
{{ protocol }}://{{ domain }}/#/passwordResetConfirm/{{ uid }}/{{ token }}
#AbimaelCarrasquillo's solutions works but you probably do not want to expose those endpoints as #dpstart mentioned in the comments.
I solved this by overriding the PasswordResetSerializer of rest-auth and simply replacing the reset form:
password_reset_form_class = PasswordResetForm
from the internal django.contrib.auth.forms.PasswordResetForm to allauth.account.forms.ResetPasswordForm
Make sure to add the following to your settings:
REST_AUTH_SERIALIZERS = {
'PASSWORD_RESET_SERIALIZER':'path.to.PasswordResetSerializer'
}
For those who are still struggling with this issue, I found that the reverse look up internal view looks for reverse lookup within the core project urls and not within any application. It could work within application with some tweak, but I am not sure. But it works creating the reset urls directly on core project urls.py
{
path(r'password_reset/', PasswordResetView.as_view(template_name='password_reset_form.html'), name='password_reset'),
path(r'password_reset_done/', PasswordResetDoneView.as_view(template_name='password_reset_done.html'), name='password_reset_done'),
path(r'password_reset_confirm/<uidb64>/<token>/', PasswordResetConfirmView.as_view(template_name='password_reset_confirm.html'), name='password_reset_confirm'),
path(r'password_reset_complete/', PasswordResetCompleteView.as_view(template_name='password_reset_complete.html'), name='password_reset_complete'),
}
Well I was also facing this problem. Every time I entered my email and pressed the button it took me to NoReverseMatch url, and I am using:
re_path(r'^password-reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
TemplateView.as_view(template_name="password_reset_confirm.html"),name='password_reset_confirm')
(url is not used to match regex in django anymore re_path is used)
My solution is to change the regex a little bit because the "csrf token" is longer than 20 words – that's why I was getting an error and you should try the same.
re_path(r'^password-reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,40})/$',
TemplateView.as_view(template_name="password_reset_confirm.html"),
name='password_reset_confirm')
You can either use + (in regex it means one or more) or {1,40} (in regex it means match from 1 to 40)
Add this to your project url.py file
url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
url('', include('social.apps.django_app.urls', namespace='social')),
Check out the FAQ: It explains this error and how to fix it. It references you to the demo program which contains:
# this url is used to generate email content
url(r'^password-reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
TemplateView.as_view(template_name="password_reset_confirm.html"),
name='password_reset_confirm'),
My solution was to override the email template that calls the reverse of "password_reset_confirm". Make sure email template sends a URL to your frontend app with the UID and Token in the URL (instead of trying to reverse "password_reset_confirm").
Your frontend's route should take the URL, parse it and then with the updated user's password and send it back as an API call to your backend to confirm.
I resolved this issue by moving these:
path('reset_password/', auth_views.PasswordResetView.as_view(), name='password_reset'),
path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
path('reset_password_sent/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
path('reset_password_complete/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
from accounts/urls.py to yourProjectName/urls.py.
I guess that path('', include("accounts.urls")), was causing the problem.
I have a headless backend, so adding or renaming URLs only for this was not a good option.
The issue is on the email template, you can override it. Just take care that you have the correct path on the settings.
In my case I have all this logic inside users app. So I have something like this.
users/templates/registration/password_reset_email.html
Inside this template I have a new custom message without the reverse URL call.
If you need more than just override the template, or maybe you need to send additional data to the template. You must override the serializer also. To do that you have to create your new serializer
from dj_rest_auth.serializers import PasswordResetSerializer as RestPasswordResetSerializer
class PasswordResetSerializer(RestPasswordResetSerializer):
def get_email_options(self):
return {
'html_email_template_name': 'registration/password_reset_email_html.html', # if you want to use an HTML template you can declare here
'extra_email_context': {'custom_key': 'custom value for my template',}
}
and add to settings.
REST_AUTH_SERIALIZERS = {
'PASSWORD_RESET_SERIALIZER':'path.to.PasswordResetSerializer'
}
On the serializer you can add custom validation if needed also.
In your views.py, if you have set a token, pass it along with the path similar to:
path('resetpassword_validate/<uidb64>/<token>/', views.resetpassword_validate, name='resetpassword_validate'),

Getting 403 error on url while sending POST

I am getting started with a django based simple ajax enabled web app.
I am able to launch the hompage. From homepage when i try to hit another url I am getting 403 error
My index page is http://mydomain.com/SampleApp - This works fine
My Ajax url is http://mydomain.com/SampleApp/ajax - This gives 403 error
Please replace 'mydomain.com' in above urls with proper localhost:8000 as it is restricted.
The error shown is
CSRF verification failed. Request aborted.
Reason given for failure:
CSRF cookie not set.
I think I am missing some important setting in settings.py
Adding the source code
URL Conf
url(r'^SampleApp/', include('views.urls'))
views.url.py
urlpatterns = patterns('',
url(r'^ajax/$', views.ajax),
url(r'^$', views.index)
)
views.views.py
def index(request):
print('Rendering Index')
return render(request, 'index.html')
def ajax(request):
print('rendering ajax')
return render(request, 'ajax.html');
For the sake of brevity, I have excluded the imports
It's look like you did not put csrfmiddlewaretoken in your ajax request.
The easiest way to include it is:
var data = {
'csrfmiddlewaretoken': $('input[name="csrfmiddlewaretoken"]').val(),
// any other data
},
url = '/api/create/';
$.ajax({
type: 'POST',
url: url,
data: data,
...
And don't forget to include {% csrf_token %} in your template of page from which the ajax request is sent (like index.html)
Or you can decorate your view by #csrf_exempt decorator:
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def ajax(request):
print('rendering ajax')
return render(request, 'ajax.html');
This allows you to exclude csrfmiddlewaretoken from ajax request
Hope that'll help you.

Categories

Resources