Closed shamszzazzo closed 2 years ago
@shamszzazzo I gave this a thought and it would indeed help to at least have some handgrips to get started.
I'm working on a javascript example with the fetch
API. and how you should / could configure django-rest-framework
to make this possible. I'll keep you posted in the following weeks.
@shamszzazzo There a few reasons:
Also, don't use session authentication. Use something like django-knox.
Thank you for that, yes I use the same domain name and there it works. and I already use them in the setting.
- CSRF_COOKIE_SECURE = True
- SESSION_COOKIE_SECURE = True
- CORS_ALLOW_CREDENTIALS = True
- SESSION_COOKIE_SAMESITE = "None"
- CSRF_COOKIE_SAMESITE = "None"
CORS_ALLOWED_ORIGINS = [
'http://127.0.0.1:3000',
'http://localhost:3000',
'https://mydomain.com',
]
but I am already using session authentication that oscar gives in by default. So should I change to django-knox. ?
I think Oscar API is supposed to work best when your frontend is already inside Django (or share the same domain). If you have a separate frontend on a different domain, I would suggest moving away from session authentication. It's not easy to set up and not recommended in that case.
There is nothing special about session authentication. It's just a middleware that can be easily replaced. But there is a caveat: when you move to django-knox, your basket will no longer persist for unauthenticated users. Every request will generate a new basket. This can solved by creating your own basket views and maybe save the basket ID in cookies on the frontend. Then there are basket permission issues but explore the idea and see how it goes.
@farooqaaa so the idea is to use make my own custom authentication and session views for basket and others?
well, I have already done authentication but my problem is I can't read cookies from frontend because it httponly, besides, there is a CSRF issue when I need to log out (delete request in login).
All I want is to use session authentication and add and remove items from the basket but I can't because of the CSRF problem when I request logout (delete request in login) and after login tries to add something in the basket.
{
"detail": "CSRF Failed: Referer checking failed - no Referer."
}
If you want to stick to Session Authentication still then I guess something like this could work:
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SAMESITE = 'None'
SESSION_COOKIE_SAMESITE = 'None'
Try these settings.
If you want to use oscarapi (or any restframework application):
For the first scenario I implemented a simple example how to login and fetch the basket. You can see if you are logged in by inspecting the owner
field of the basket. if it's set, you are logged in. You can see this by clicking the "Fetch basket" button.
This example is now added to the sandbox.
Note that I have to send the CSRF
token while communicating with the API..
This is explained in newer versions of the django documentation: https://docs.djangoproject.com/en/4.1/howto/csrf/#setting-the-token-on-the-ajax-request
If you want to use oscarapi (or any restframework application):
- From a view in Django -> Session authentication
- Any other situation -> Use tokens / JWT. You will need to set the correct CORS headers with django-cors-headers and do some session handling mechanism yourself.
For the first scenario I implemented a simple example how to login and fetch the basket. You can see if you are logged in by inspecting the
owner
field of the basket. if it's set, you are logged in. You can see this by clicking the "Fetch basket" button.This example is now added to the sandbox.
Note that I have to send the
CSRF
token while communicating with the API..This is explained in newer versions of the django documentation: https://docs.djangoproject.com/en/4.1/howto/csrf/#setting-the-token-on-the-ajax-request
Thanks for your effort,
it gives a good understanding of ajax requests for OscarAPI.
But I still face problems with connecting ReactJS. I did log in with reactJS, where my session and CSRF go-to cookies. So, When I try to delete a request in login it shows:
fetch(loginURL, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": cookies.get("csrftoken"),
},
credentials: "same-origin"
})
.then(res => res.json())
.then((data) => {
console.log(data);
// this.setState({isAuthenticated: true, username: "", password: "", error: ""});
})
.catch((err) => {
console.log(err);
// this.setState({error: "Wrong username or password."});
});
it shows me success(delete request) but shows how don't delete cookies session. so it not properly works. Please help me to solve this issue.
in my setting.py.
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = False # False since we will grab it via universal-cookies
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "None"
CSRF_COOKIE_SAMESITE = "None"
CORS_ALLOWED_ORIGINS = [
'http://127.0.0.1:3000',
'http://localhost:3000',
'http://192.168.3.72:3000',
]
CORS_EXPOSE_HEADERS = ['Content-Type', 'X-CSRFToken']
CORS_ALLOW_CREDENTIALS = True
I updated the example with a Logout button and it now reads the CSRF token from the cookie (it changes of course after a POST
or DELETE
).
This is documented in the django docs: https://docs.djangoproject.com/en/4.1/howto/csrf/#acquiring-the-token-if-csrf-use-sessions-and-csrf-cookie-httponly-are-false
See the fulll example here: https://github.com/django-oscar/django-oscar-api/blob/6e2f7f994ad2fdddeba8fce8c337d811530a04fe/sandbox/templates/js-login-example.js
Please test it yourself with the sandbox.
I'll write some documentation regarding this the following weeks.
I updated the example with a Logout button and it now reads the CSRF token from the cookie (it changes of course after a
POST
orDELETE
).This is documented in the django docs: https://docs.djangoproject.com/en/4.1/howto/csrf/#acquiring-the-token-if-csrf-use-sessions-and-csrf-cookie-httponly-are-false
See the fulll example here: https://github.com/django-oscar/django-oscar-api/blob/6e2f7f994ad2fdddeba8fce8c337d811530a04fe/sandbox/templates/js-login-example.js
Please test it yourself with the sandbox.
I'll write some documentation regarding this the following weeks.
Sorry to say I try many ways but it won't delete Session id and CSRF token from cookies even if I try to logout(delete request)
login delete request:
def delete(self, request, *args, **kwargs):
"""
Destroy the session.
for anonymous users that means having their basket destroyed as well,
because there is no way to reach it otherwise.
"""
request = request._request
if request.user.is_anonymous:
basket = operations.get_anonymous_basket(request)
if basket:
operations.flush_and_delete_basket(basket)
request.session.clear()
request.session.delete()
request.session = None
return Response("")
maybe here need some change like response.delete_cookie or something.
it won't delete Session id and CSRF token from cookies
And how do you determine that this is not the case?
It isn't deleting the session cookie, I'm investigating now why this is
I forgot to remove a line in the example, so if you did try the sandbox example you should pull the main branch again.
Here is a scenario that I think is doing what you are expecting.
1) I login with a user:
You can see the response cookies csrftoken
and sessionid
are set:
2) logout with the DELETE
command:
You can see that request
cookies are the same as before. This makes sense as we are calling the DELETE
before the session has been deleted on the server. You can also see there are no response cookies.
3) fetch the basket:
You can see that the user is not logged in anymore because the owner
is not set. You can also see that there is a new sessionid
cookie set in the response, with a different value as the first one. At this point, we have a new (anonymous) session, as the old one was deleted. Django will detect that the earlier session cookie is not valid and sends back a new one.
So I think there is no explicit need for deleting the cookies, as they are overridden with new ones when needed. Session renewal is also depending on how you are maintaining sessions, so it's not a case of adding delete_cookie
to the delete view, as sessions could also be maintained in many other ways.
I do however, would expect that the session cookie will be deleted. See the middleware of django which should do it:
Ok I figured out that the current implementation of the delete view is deleting too much so the standard django middleware isn't able to expire the session cookie.
I'm working on a PR to fix is, the result is that an expired cookie will be set by the django session middleware which will delete the cookie client side.
Thanks for your extraordinary effort, I will wait for it.
@shamszzazzo https://github.com/django-oscar/django-oscar-api/pull/294
This has been merged in the master branch so session cookies will be deleted when you call the delete
logout view.
@shamszzazzo Any chance you had te opportunity to test the master branch?
Trying to use react js to log in and other options but the problem is httponly session can't access by any kind of js even use withCredentials: true.
please give good documentation to communicate with API with js frameworks. or at least js.