How to use g.user global in flask

65,034

Solution 1

g is a thread local and is per-request (See A Note On Proxies). The session is also a thread local, but in the default context is persisted to a MAC-signed cookie and sent to the client.

The problem that you are running into is that session is rebuilt on each request (since it is sent to the client and the client sends it back to us), while data set on g is only available for the lifetime of this request.

The simplest thing to do (note simple != secure - if you need secure take a look at Flask-Login) is to simply add the user's ID to the session and load the user on each request:

@app.before_request
def load_user():
    if session["user_id"]:
        user = User.query.filter_by(username=session["user_id"]).first()
    else:
        user = {"name": "Guest"}  # Make it better, use an anonymous User instead

    g.user = user

Solution 2

Minor correction, the g object is bound to the application context now instead of the request context.

"Starting with Flask 0.10 this is stored on the application context and no longer on the request context which means it becomes available if only the application context is bound and not yet a request."

Share:
65,034
Mittenchops
Author by

Mittenchops

Updated on July 08, 2022

Comments

  • Mittenchops
    Mittenchops almost 2 years

    As I understand the g variable in Flask, it should provide me with a global place to stash data like holding the current user after login. Is this correct?

    I would like my navigation to display my user's name, once logged in, across the site.

    My views contain

    from Flask import g #among other things
    

    During login, I assign

    user = User.query.filter_by(username = form.username.data).first()
    if validate(user):
        session['logged_in'] = True
        g.user = user
    

    It doesn't seem I can access g.user. Instead, when my base.html template has the following...

    <ul class="nav">
        {% if session['logged_in'] %}
            <li class="inactive">logged in as {{ g.user.username }}</li>
        {% endif %}
    </ul>
    

    I get the error:

    jinja2.exceptions.UndefinedError
    UndefinedError: 'flask.ctx._RequestGlobals object' has no attribute 'user'
    

    The login otherwise works fine. What am I missing?

  • Mittenchops
    Mittenchops over 11 years
    Thanks, Sean, that clarifies for me what's going on with g. I don't suppose you have further comment on what is the insecure part about sessions and how to implement this better with Flask-Login? Is the solution so simple as use Flask-Login and then using the session[] variable is then secure? Would you recommend against using g at all as seen in the tutorial I linked to?
  • Sean Vieira
    Sean Vieira over 11 years
    @Mittenchops - Flask-Login still uses session - it simply deals with all the corner cases of managing login / logouts, forcing re-authentication when necessary, etc. The potential of getting those corner cases wrong is what makes your application less secure. g is safe to use regardless - it is not constructed out of user-provided data and so may be considered "safe".
  • Mittenchops
    Mittenchops over 11 years
    Sean, can I follow up one thing on this? Suppose I'm using the kvsession to secure my cookies (rather than simply to sign them). Is there then any benefit using g instead of session? Is there some esoteric difference in memory usage or something whether I set session["user"] or g.user?
  • Sean Vieira
    Sean Vieira over 11 years
    @Mittenchops - as long as what you are storing is serializable session is probably a better bet (simply because g is torn down at the end of every request while session is preserved between requests). So, assuming that User could be serialized you could do: if "user" not in session: # query database and avoid numerous calls to the DB (An un-enhanced g would require a DB call on every request since it is always built afresh).
  • Emil Vatai
    Emil Vatai over 9 years
    Since I'm a bit new to web development, may I check if I understand everything? I should use session['key']='value' if 'value' is a string (or something which can be stored as a string), and use g.key = value is values is a bit more 'complicated' python object (or something what is not storable as a string). And session will be stored per connection 'until the browser is closed', and g will be deleted for each request i.e. for each 'enter' pressed in the address bar.
  • FabioCosta
    FabioCosta over 8 years
    So the g will be the same on every request on the same proccess ? So if i send a request and save something on 'g' and another request cames ths value would still be there ?
  • pors
    pors almost 8 years
    @FabioCosta nope, you still need the session for that
  • Antoine Lizée
    Antoine Lizée over 7 years
    It seems from the code that g is not defined per request but per app context. That makes a hell of a difference.
  • Sean Vieira
    Sean Vieira over 7 years
    @AntoineLizée - that is correct now - at the time this answer was written though it was not (appcontext was added in the 0.10 release, which came out the month after this answer was written). I'll update.
  • Sean Vieira
    Sean Vieira over 7 years
    In either case, what is on g is done for each request (you can't share values across requests on g).
  • colidyre
    colidyre almost 7 years
    Better yet: get rid of flask -- wtf?