15

I tried to implement GAE's webapp2 session, but there seems very little documentation about it. According to http://webapp-improved.appspot.com/api/webapp2_extras/sessions.html, my steps are as follows:

1.Configure and add config to the main application:

config = {}
config['webapp2_extras.sessions'] = {
    'secret_key': 'my_secret_key',
}
app = webapp2.WSGIApplication([...], config=config)

2.Create session in the login handler

# Delete existent session
  --> not mention in the tutorial
# member is found    
self.session_store = sessions.get_store(request=handler.request)
self.session['account'] = member.account

3.Check if a session exists at various locations in my program

if self.session['account']:
    # Session exists

4.Delete session when user logs out

--> not mentioned in the tutorial

My questions:

  1. I got error message " ... object has no attribute 'session'" during the session creation process (Step 2)

  2. How do I delete a session in steps 2 and 4?

  3. Is the overall session management process correct?

Thanks.

Randy Tang
  • 4,283
  • 12
  • 54
  • 112

3 Answers3

16

Here is an example of the handler and how to use webapp2 extra sessions

main.py with the BaseHandler and a MainHandler

import webapp2
from webapp2_extras import sessions

class BaseHandler(webapp2.RequestHandler):              # taken from the webapp2 extrta session example
    def dispatch(self):                                 # override dispatch
        # Get a session store for this request.
        self.session_store = sessions.get_store(request=self.request)

        try:
            # Dispatch the request.
            webapp2.RequestHandler.dispatch(self)       # dispatch the main handler
        finally:
            # Save all sessions.
            self.session_store.save_sessions(self.response)

    @webapp2.cached_property
    def session(self):
        # Returns a session using the default cookie key.
        return self.session_store.get_session()

class YourMainHandler(BaseHandler):

    def get(self):

        ....
        self.session['foo'] = 'bar'


    def post(self):


        foo = self.session.get('foo')

And if you have a seperate login.py :

.... other imports
import main

class Login(main.BaseHandler):

    def get(self):

        ....
        self.session['foo'] = 'bar'


    def post(self):


        foo = self.session.get('foo')
voscausa
  • 11,253
  • 2
  • 39
  • 67
  • Appreciate your help very much. I'm still struggling, but with no luck. Suppose I have a module "login.py" with class Login(webapp2.RequestHandler) in it for handling user log in. There is also a main module "main.py" with class MainPage(BaseHandler) in it. How do I change the Login class? I import main in login.py, and change class Login(webapp2.RequestHandler) into Login(main.BaseHandler). Error message: 'module' object has no attribute 'BaseHandler' – Randy Tang Dec 29 '12 at 17:41
  • That's what I was talking about: error message: 'module' object has no attribute 'BaseHandler' – Randy Tang Dec 30 '12 at 02:29
  • When checking the existence of a user, I don't really need the username of the session. Hence, "foo = self.session.get('foo')" doesn't seem to do the job. How do I do that then? Furthermore, how do I delete a user's session (also without knowing the username)? Thanks a log. – Randy Tang Dec 30 '12 at 02:56
  • 1
    I suggest you study sessions and webapp2. To give you a final hint : when the user ends his session, do not write / save the session and delete the session cookie. – voscausa Dec 30 '12 at 11:55
  • re: The basehandler issue, suggest until you obtain more expertise you just keep everything in the same file. – Paul Collingwood Dec 30 '12 at 12:11
  • Yes, I do need to do more research on webapp2 and sessions. But the problem is: the link I mentioned in my question is the only documentation I could find. And I have to say, the documentation is very lousy; it doesn't give too much information. Perhaps you could give some more directions. Thanks in advance. – Randy Tang Dec 31 '12 at 12:08
  • @ Paul C: I am currently working on a project which contains thousands of lines of code. It wouldn't be possible to put everything in one file ;-) I'll do more research on the subject anyway. Thank you. – Randy Tang Dec 31 '12 at 12:10
5

This may not be a direct answer to the question, but it is a solution I found using gaesessions instead of GAE's webapp2 session and I would like to share with everybody. Here we go:

  1. Download gaesessions from https://github.com/dound/gae-sessions by clicking "Download ZIP" button. The downloaded file is "gae-sessions-master.zip".

  2. Unzip the file (a directory "gae-sessions-master" will be created), and copy the directory "gaessions" to the root directory of your application (i.e., where "app.yaml" is)

  3. Create a file called "appengine_config.py" in the root directory, with the following content (copied form https://github.com/dound/gae-sessions/tree/master/demo):

    from gaesessions import SessionMiddleware
    
    # Original comments deleted ... 
    # Create a random string for COOKIE_KDY and the string has to
    # be permanent. "os.urandom(64)" function may be used but do
    # not use it *dynamically*.
    # For me, I just randomly generate a string of length 64
    # and paste it here, such as the following:
    
    COOKIE_KEY = 'ppb52adekdhD25dqpbKu39dDKsd.....'
    
    def webapp_add_wsgi_middleware(app):
        from google.appengine.ext.appstats import recording
        app = SessionMiddleware(app, cookie_key=COOKIE_KEY)
        app = recording.appstats_wsgi_middleware(app)
        return app
    
  4. Create a session when a user logs in (variable account is the user's account):

    from gaesessions import get_current_session
    session = get_current_session()
    if session.is_active():
        session.terminate()
    # start a session for the user (old one was terminated)
    session['account'] = account
    
  5. Check if the user's session exists, if yes, return user's account:

    from gaesessions import get_current_session
    def checkSession():
        session = get_current_session()
        if session.is_active():
            return session['account']
        return False
    
  6. Delete the session when the user logs out:

    def logout():
        session = get_current_session()
        if session.is_active():
            session.terminate()
    
  7. Finally, you may create a cron job to clean expired sessions periodically:

cron.yaml:

- description: daily session cleanup
  url: /clean_up_sessions
  schedule: every day 3:00
  timezone: ... (Your time zone)

Function:

from gaesessions import delete_expired_sessions
class clean_up_sessions(webapp2.RequestHandler):
    def get(self):
        while not delete_expired_sessions():
            pass

Hope this helps.

Randy Tang
  • 4,283
  • 12
  • 54
  • 112
  • 2
    Why using gae-sessions instead of webapp2_extras.sessions? gae-sessions compares itself to a few session systems but not to webapp2's sessions. – Romz Feb 10 '14 at 18:12
  • Thanks a lot, Romz. I didn't aware that there is webapp2_extras.sessions. I'll give it a try. – Randy Tang Feb 11 '14 at 18:50
  • In my app auth create a Unique model in datastore and it saves a key in the and UserToken and when user change the password and logout he is not able to login again – Jaskaran singh Rajal Nov 20 '18 at 14:40
3

In your RequestHandler override dispatch: from webapp2_extras import sessions

def dispatch(self):

    self.session_store = sessions.get_store(request=self.request)

    try:
        webapp2.RequestHandler.dispatch(self)
    finally:
        self.session_store.save_sessions(self.response)

and make a webapp2.cached_property called session:

@webapp2.cached_property
def session(self):
    return self.session_store.get_session(backend="<whatever you want here>")

When you want to access session values, you do self.session[<key>]

When a user logs in, you can call either:

 self.auth.get_user_by_password(auth_id, password, remember=True,
                                           save_session=True)

which will take care of getting rid of the old session and creating the new one for you, or:

self.auth.set_session(self.auth.store.user_to_dict(self.user), remember=True)

As far as logging out, all you should need to call is:

self.auth.unset_session()
Eliezer
  • 7,209
  • 12
  • 56
  • 103