Cannot access cookies after redirect in django - python

Here is situation I've dealt with. I will try to explain as much as easier to understand.
I want user to click on a button in the website (let's name this site A) which fires an ajax post request to django view. Within this view I have response.set_cookie to set cookie with data that is passed along with ajax post request.
After success response, then I quickly redirect page to different website (let say this site is B). When page loads, I want to access cookies what I've set from site A but cannot access.
Below is my code.
index.html (in site A, where the ajax post request is made)
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<button onclick=setCookies()>Create Invoice</button>
</body>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script type="text/javascript">
const setCookies = () => {
...some codes...
const xhr = new XMLHttpRequest()
const data = {
'HTTP_LOGIN_TYPE': 'admin',
}
$.ajax(
{
type: 'POST',
url: url, // hits endpoint where sets cookies.
crossDomain: true,
data: data,
success: () => {
window.location.href = to site B
},
error: xhr => {
console.log(xhr.responseText)
}
}
)
}
</script>
</html>
views.py (in site B, where sets the cookies)
from django.http import HttpResponse
from django.conf import settings
from rest_framework.views import APIView
class AuthenticateUser(APIView):
def post(self, request):
data = request.POST
login_type = data['HTTP_LOGIN_TYPE']
if login_type == 'admin':
response = HttpResponse(
'Setting login_type to %s' % login_type)
response.set_cookie(
'login_type', login_type, max_age=604800, domain=settings.SESSION_COOKIE_DOMAIN)
return response
views.py (in site B, redirected from ajax call in index.html, where I want to access cookies)
import re
from django.db import DatabaseError
from rest_framework.response import Response
from rest_framework.renderers import TemplateHTMLRenderer
from rest_framework.views import APIView
class GetInvoice(APIView):
renderer_classes = [TemplateHTMLRenderer]
template_name = 'student/base.html'
def get(self, request, student_id):
login_type = 'hello'
if 'login_type' in request.COOKIES:
login_type = request.COOKIES['login_type'] # Can't access cookies
... more code ...
FYI, url in index.html and site B's domain are same, though site A and B's domains are different.
I am not sure what am I missing. I've been searching articles, posts, etc for last couple days and tried based on them but no luck.
Correct me if I missed anything.
Thanks in advance.

Because of the Same-origin Policy, you cannot access the cookies for a different domain.
Access to data stored in the browser such as localStorage and
IndexedDB are separated by origin. Each origin gets its own separate
storage, and JavaScript in one origin cannot read from or write to the
storage belonging to another origin.
However, if domain B is a subdomain of A, it will automatically have visibility into the cookies for domain A. If you cannot change the domains, you should redirect to site B with the cookies in the request headers/body.

Related

Forbidden (CSRF cookie not set.) Django

I'm trying to do an endpoint API. And for that, i'm using django.
My url in urls.py is :
path('tutorials/', tutorial_list_test.as_view()),
and my views.py is like
class tutorial_list_test(GuestOnlyView, FormView):
print("test");
#api_view(['GET', 'POST', 'DELETE'])
def tutorial_list(self):
request = self.request;
if request.method == 'POST':
alldata=request.POST
username = alldata.get("username", "0")
print("POST name: " + username)
return Response('The tutorial does not exist', status=status.HTTP_404_NOT_FOUND)
But when i'm doing a request, i have everytime the same error "Forbidden (CSRF cookie not set.): /accounts/tutorials/"
So I did some research, and I could see several proposed solutions.
The first was to use csrf_exempt but it's not working for me:
path('tutorials/', csrf_exempt(tutorial_list_test.as_view())),
And it's the same for all the methods I used. Even if I remove this line from my settings.py, nothing changes
# django.middleware.csrf.CsrfViewMiddleware',
To test, I use Postman, but even using my angular front end, it does the same.
const formData = new FormData()
formData.append('username', this.username_signup);
this.http.post('http://127.0.0.1:8000/accounts/tutorials/', formData)
.map((data: Response) => {
if (data !== null) {
console.log(JSON.stringify(data));
};
}).subscribe(response => console.log(response))
I would like to know if you have any idea how I can do this.
Because I need to be able to access my Models, so not using a class and directly making a def is not an option, even if it works.
(I tried, effectively my requests pass, if I remove the class and my route is only linked to my def tutorial_list).
Thank you.
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
#api_view(['GET', 'POST', 'DELETE'])
def tutorial_list(self):
# code

Django redirects - how to handle redirect when using ajax

I need return redirect(url) or something like this in django, and force template to do to this url.
It returns me template html-code instead when EXACTLY redirect is required.
Any ideas? Now i have to write redirect in templates window.location='url' , it works, but make code tangled.
django.__version__ == '2.0.1'
I need django text, that does like javascript window.location='myurl'
Part of view
#csrf_exempt
def CheckState(request):
...
try:
... if (condition):
a = redirect('/mypage/')
...
return a #redirect('http://localhost:port/mypage/')
part of template (js.code)
$(document).ready(function() {
$.get('/my/CheckState/', {})
.success(function(data){
console.log(data);
//window.location = 'url' works here, otherwice no redirect!
//In console i see html-code of 'http://localhost:port/mypage/'
})
.error(function(xhr, textStatus, errorThrown){
console.log(xhr.responseText);
})
--comment--
a._headers = {'content-type': ('Content-Type': 'text/html; charset=utf-8'),
'location' : ('Location', '/mypage' )}
I saw this header before i asked question, but problem exists - no jump doing. Why is this redirect not working?
It's not possible to prevent $.get() (which uses Xmlhttprequest) from following the redirect. See this question for an explanation.
You might be able to use the fetch API which does allow you to prevent redirects.
If you can't do that, you could change the view to return the new URL in the response,
from django.http import JsonResponse
def CheckState(request):
return JsonResponse({'status': 'redirect', 'url': '/new/url/'})
...
Then in your ajax handler, check the response for status=redirect, and if so set window.location to the url.

Don't render whole template with Flask

i'm always using the standard Flask-command render_template(), well, to render my templates. The whole template is just static, but there is one form, which is changing after user's input and one image-slider. Now the issue: When the user submits his/her input the wohle template gets re-rendered.
Is it possible that i just update the form-data and leave the rest of the page untouched?
My template looks like that:
<html>
<head>
</head>
<body>
<form action="/" method ="POST" id="Form">
{{msform.ms_1}} is to {{msform.ms_2}} like {{msform.ms_3}} is to {{msform.ms_submit}}
</form>
</body>
</html>
My views.py follows:
#app.route('/', methods=(['GET','POST'])
def index():
if request.method == 'POST':
msform = msForm(request.form, prefix='ms')
msform.ms_submit.label.text= msform.ms_3.data + msform.ms_2.data
return render_template(template, msform=msform)
return render_template(template, msform=msform)
Where should i place the first answer? Thanks, FFoDWindow
If you want the form to send a request with the data without reloading the whole page, then the solution is to send the form data using a XHR request (AJAX request) using JavaScript.
There's no way for the server to refresh just a portion of a template after it's been sent to the browser. HTTP is stateless, so after your browser makes the submit request, the server replies with the template you render, and that's it.
If you need to "replace" or "re-render" just a portion of the page without doing a full page reload, you need JavaScript and and XHR request.
You would need to create a Flask endpoint to receive the POSTed data.
Example using jQuery:
$("#your-form").submit(function(e) {
e.preventDefault(); // Prevent the normal form submit
$.ajax({
type: "POST",
url: '/your-api',
data: $("#your-form").serialize(),
success: function(data) {
// Do something here. For example, the server can return JSON here and you use Js to create the template client-side, or you server can return an HTML fragment and here you append it to a dom node
}
});
});
Normally, these kind of endpoints returns JSON, but if you want to stick with your server side templates as much as possible, you could return the re-rendered form as a response to the AJAX call, and then append with jQuery that response into the container element, effectively replacing the form.
Let's say you're using Jinja2 as a template engine. Then you can have a partial for the form which you normally include in the main template when you render the full page the first time.
You then can render just the same partial when you respond to the AJAX request on submit.
Hope this is helpful.

Tornado redirecting to page with parameters

I'm using self.render to render a html template, which is dependent on the information received from the client via ajax in the def post() method like this:
class aHandler(BaseHandler):
#tornado.web.authenticated
def post(self):
taskComp = json.loads(self.request.body)
if taskComp['type'] == 'edit':
if taskComp['taskType'] == 'task':
self.render(
"tasks.html",
user=self.current_user,
timestamp='',
projects='',
type='',
taskCount='',
resName='')
However this does not redirect the user to the html page 'tasks.html'.
However I see in my console a status:
[I 141215 16:00:55 web:1811] 200 GET /tasks (127.0.0.1)
Where '/tasks' is an alias for tasks.html
Why wouldn't this be redirected?
Or how can data received from ajax, then be used to redirect to the tasks.html page along with all the parameters supplied in the above self.render request?
"render" never redirects a visitor's browser to a different URL. It shows the browser the contents of the page you render, in this case the "tasks.html" template.
To redirect the browser:
#tornado.web.authenticated
def post(self):
self.redirect('/tasks')
return
More info in the redirect documentation.
To redirect using an AJAX response, try sending the target location from Python to Javascript:
class aHandler(BaseHandler):
#tornado.web.authenticated
def post(self):
self.write(json.dumps(dict(
location='/tasks',
user=self.current_user,
timestamp='',
projects='',
type='',
taskCount='',
resName='')))
Then in your AJAX response handler in Javascript:
$.ajax({
url: "url",
}).done(function(data) {
var url = data.location + '?user=' + data.user + '&timestamp=' + data.timestamp; // etc.
window.location.replace("http://stackoverflow.com");
});
More about URL encoding is at this answer.

Issues with ajax in django

I'm using ajax in django first times .. I read some tutorials on the net and I'm trying to make a simple form which posts some information via ajax.
Here is my html form
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
function send_request()
{
$.ajax({
type:"POST",
url:"/ajaxredirect/",
});
}
</script>
<button type="button" onclick="send_request();">change content</button>
and it is my view
def Ajaxquery(request):
if request.is_ajax():
return HttpResponse("ok")
else:
return HttpResponse("error")
it does nothing when i am click on change content button in browser.
Any suggestions would be apperciated
Here is basic request/response setup I have made use of. I got the JSONResponse and AjaxResponse mixins from the Django Braces Module. I also made sure to include the following Django CSRF fix to prevent my AJAX request from being treated as a cross site request forgery.
JQuery:
<script type="text/javascript">
function send_request() {
$.ajax({
type: 'POST',
url: '/ajaxredirect/',
data: $('#your_form').serialize(),
crossDomain: false,
success: function(ctx) { console.log(ctx); },
});
}
</script>
Views.py
from django.views.generic import View
from braces.views import JSONResponseMixin, AjaxResponseMixin
class AjaxResponseView(JSONResponseMixin, AjaxResponseMixin, View):
def post_ajax(self, request, *args, **kwargs):
data = request.POST.items() # form data
ctx = {'hi': 'hello'}
return self.render_json_response(ctx)

Categories

Resources