In Django, what would be the proper way to persist session information? - django

I am designing a REST app in django, which I intend people to use without a browser (just direct API calls with curl or whatnot). I have several different views where I want to pull in information about the session based on values that may have been a acquired from previous calls to other views. It seems that every time a view is called the "request" object passed in is an entirely new session, so I'm wondering how I can persist values the "correct" way?
Example code:
def login(request):
...
##I want to assign a token value to this session that is persisted to the entity requesting it
request.session['token'] = response.json()['auth']
...
def grabSomeValues(request):
...
##I want to grab the session token value in here but of course the request object in the case is a completely new one that does not have that token value it seems
print(request.session['token']
....

I think Middleware would help you.
The session framework lets you store and retrieve arbitrary data on a per-site-visitor basis.
https://docs.djangoproject.com/en/2.2/topics/http/sessions/

Related

How to validate OAuth2 State in Django?

I looked at the GitHub OAuth API and saw that one requirement to send to the endpoint is state.
Sending it is trivial - but how do you validate that the state you sent is the same one you’re receiving?
I thought of using browser caching but it seems like it’s for views of Django and improving performance.
I thought of sending a CSRF token as the state but it seems it’s meant for forms you generate.
In short, how do you validate state in Django? Is there a Pythonic way in Django to do so?
The user's session is the best place to store variables that are session related, which is the case here.
So generate your state and store it into the user's session:
request.session['github_state'] = state
return render(<template with github link>, context={'state': state})
Then when you receive the user's authorised GET request:
if request.session.get('github_state') and not request.GET.get('state') == request.session['github_state']:
# abort here
else:
code = request.GET.get('code')
# POST request with code to GitHub to fetch the access token
I'm checking that the session variable isn't empty/None, otherwise both might be empty and the check would pass.

A signal that a session has been created ? [for anonymous user]

I can't seem to find the the signal that tie with a 'session created' .
I'm aware of auth signals , but what i want is to populate a session variable for anonymous users.
What am i missing ?
Thanks in Advance
To store a session variable for anonymous users, you can do something as simple as request.session['something'] = True (or whatever value you want) in the appropriate view. And if you're trying to see if you've seen an anonymous user before, you can just test for the existence of the 'something' key.
Under the hood, django handles cookie setting and creates a session for an anonymous user if you modify the session variable. If the anonymous user already has a session, it simply records the modified state.
Take a look at the session docs: https://docs.djangoproject.com/en/dev/topics/http/sessions/ for more details. It's pretty sophisticated.
Finally, don't forget to clean expired sessions periodically with ./manage.py clearsessions if sessions are stored in a persistent store.

How Can I retain session information once a user registers (Django)?

When a new user is created, I want to retain some of the information in their session
e.g. things a user has stored in their session I want to use once they have registered (or logged in).
I would use either a post_save signal on the user model (or an auth login signal), but it appears that the signals don't put the request, or session into the signal sent. It also seems I can't easily get the session from just the user.
I'm using Django 1.4
Edit: let me give an example.
The problem boils down to this - I may want to retain information for a user's activities before they login, but where do I store this information before they login? A good place would be a session (or I could link the data held in a db to the session, using the session a little like a makeshift user).
In any case, until they login, I can simply use their session like a user credential, and store information that persists so long as their cookie does (how else can could I reliably track an anonymous user?).
But once they register (or log-in), I want to move that information from the session, into the account properly. One good reason is that it would make sense to delete data from anonymous users periodically, whereas registered user's data would be persisted.
To do this I simply want access to the session (could be via the request) from a handler to the new-user signal, so I can make a one-off transfer from data in the session. But the new-user signal doesn't hold the session (or request).
If you're using django.contrib.sessions and django.contrib.auth for the job, the session data should be retained automatically after login.
Moreover, the user_logged_in signal is sent along with request actually.
Edit:
So use user_logged_in signal. It carries request. Pick some specific key to store unauthenticated user's data (e.g. "_anonymous_data"). If that key is set on request.session while handeling signal, simply rewrite data on request.user.get_profile() object, call save and del request.session["_anonymous_data"].
The code to retreive it could look something like:
if request.user.is_authenticated():
user_data = request.user.get_profile()
else:
user_data = requerst.session["_anonymous_data"]
It's only a scratch of course. You don't want to hardcode session keys or write such logic in views. If you need it application wide, embed it in some abstraction class which takes request in __init__.
you could try using sessions:
https://docs.djangoproject.com/en/dev/topics/http/sessions/?from=olddocs

Editing session of another user in Django

How can I do this
request.session['key'] = 'value'
for the user which user_id is 47?
Keep in mind that I'm not currently logged in with that user, I want to do it in shell.
See the section of the Session docs entitled "Using sessions out of views".
The problem though is that Django doesn't store the user with the session (by design, for security purposes). So the only way to retrieve a session is through it's key. That key is stored with the user's client and passed to the server to associate the session with the logged in user. In other words, you're going to have a hard time determining which session belongs to which user.
More to the point, the session data is actually encrypted in the database as well, so there's not even any way to query directly for the user id stored in it. The following will work, but you'll have to query each session one by one to get the right user. Depending on how many sessions your database currently has, this could be extremely expensive. Mark as USE AT YOUR OWN RISK
from django.contrib.sessions.models import Session
from django.contrib.sessions.backends.db import SessionStore
for session in Session.objects.all():
data = SessionStore().decode(session.session_data)
if data.get('_auth_user_id') == user_id_you_want:
user_session = SessionStore(session_key=session.session_key)
# you can modify the session data here like normal, then:
user_session.save()
The answer depends entirely on the session storage/engine you're using.
So, the generic answer would be: Wherever the session is being stored, modify it there.
For the database backend: UPDATE django_session SET session_data=[whatever] WHERE session_key=[whatever];
You'll also need the session key and the AES key stored in the client browser.
Alternatively, send them to a controller that updates the session.

Django Middleware + URL's

Can a middleware check to see if a value is in the url, such as an image id ("/image/152/"), and if it is then do some checks to make sure the current user has permission to view that image and if not redirect to another url?
I had to roll my own permissions for this site I am working on and I don't want to clog up almost every view I write for the whole site with the same code, so I thought a middleware would be a good idea for this, but I'm not sure how to go about doing it.
Yes, this is possible. The django middleware docs for process_request indicate that:
def process_request(self, request)
request is an HttpRequest object. This method is called on each request, before Django decides which view to execute.
process_request() should return either None or an HttpResponse object. If it returns None, Django will continue processing this request, executing any other middleware and, then, the appropriate view. If it returns an HttpResponse object, Django won't bother calling ANY other request, view or exception middleware, or the appropriate view; it'll return that HttpResponse.
The HttpRequest object has a path attribute that will give you the URL that was requested.
If you prefer, however, note that you can also extend Django's system for authentication backends to populate the user in the request with permissions based on any arbitrary criteria, such as perhaps your hand-rolled permissions scheme. This way, you can leverage the default authentication decorators (#permission_required and #user_passes_test), and other apps/the admin site will be able to honour your permissions as well. The User object and permissions created do not need to reside in Django's user/permission tables, and can be created virtually on login; I've had a fair amount of success with this.
See Writing an authentication backend if this appeals.
If you implement authorization (Permission system) in middleware, you will end up with two options:
Check URL and allow to access
Check URL and reject access
If your requirement is that much simple, it is fine, since you don't have to touch views.
But in general, Permission system is much complex than that, for example:
User can access FOO/show_all/
But, he can't see or access foo instance, i.e, FOO/show/foo_1/
Since, he can't access foo_1 instance, we should not show them in show_all
(all foo instances)
If you want implement above 3 together, I suggest you write your own custom authorization backend for Django. All you need to do is implement few methods (your specific logic) and attach as backend.