webapp2のセッション機能を使ってみました

先日の記事で書いていたセッションのコードをwebapp2のセッション機能を使って書きなおしてみました。

コードはサンプルのものと全く同じです。

class BaseHandler(webapp2.RequestHandler):
    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)

    @webapp2.cached_property
    def session(self):
        return self.session_store.get_session()

でセッションに対応したリクエストハンドラーを定義し、webapp2.RequestHandlerの代わりにこれを継承して応答用のクラスを作成すれば

# 値をセット
self.session['foo'] = 'bar'

# 値を取得
foo = self.session.get('foo')

という方法で値を読み書きすることができます。

前回のコードではセッション用のIDを都度

# 値をセット
self.response.set_cookie('sessionID', new_sessionID, max_age=300)

# 値を取得
sessionID = self.request.cookies.get('sessionID')

という方法でcookieに保存していましたがこの部分をwebapp2の機能を使った保存方法で置き換えました。
ただし書いてみて分かったのですが今回のコードではセッション機能を利用してcookieに保存しているのはランダムに生成したセッション用のIDのみなので

new_sessionID = binascii.hexlify(os.urandom(8))

で推測できないよう生成したIDを秘密鍵を使って更に暗号化してcookieに保存するという二度手間になっているだけなのでwebapp2のセッションを使用する意味がないと思います。(^_^;)

サーバ側コード(ブラウザ側は前回のものと同じ)

# coding: utf-8

import webapp2
import cgi
import os
import binascii
import jinja2
import json
from google.appengine.ext import db
from webapp2_extras import sessions

jinja_environment = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))

config = {}
config['webapp2_extras.sessions'] = {
    'secret_key': 'abcdefg',#秘密鍵
    'session_max_age': 330
}


class UserProfile(db.Model):
    sessionID = db.StringProperty()
    name = db.StringProperty()
    words = db.StringListProperty()
    date = db.DateTimeProperty(auto_now_add=True)


class BaseHandler(webapp2.RequestHandler):
    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)

    @webapp2.cached_property
    def session(self):
        return self.session_store.get_session()


class MainPage(BaseHandler):
    def get(self):
        sessionID = self.session.get('sessionID')

        if not sessionID:
            new_sessionID = binascii.hexlify(os.urandom(8))
            session = UserProfile(sessionID=new_sessionID)
            session.name = 'GUEST'
            session.words = []
            session.put()

        template = jinja_environment.get_template('sessiontest2.html')

        self.response.headers['Content-Type'] = 'text/html;charset=utf-8'

        if not sessionID:
            self.session['sessionID'] = new_sessionID

        self.response.out.write(template.render())

    def post(self):
        self.get()


class JsonData(BaseHandler):
    """ページのJavascriptからリクエストを受けてJSONを送る
    """
    @staticmethod
    def _session_check(sessionID):
        """
        セッションIDがすでにデータストアに登録されているか確認し
        Queryを返す
        """
        sessions = (UserProfile
                    .all()
                    .filter('sessionID =', sessionID)
                    )
        return sessions

    def post(self):
        sessionID = self.session.get('sessionID')

        if not sessionID:
            raise Exception('Session Error')
            return

        session = self._session_check(sessionID)[0]
        session.name = (cgi.escape(self.request.get('newUserName')) or
                        session.name)

        if self.request.get('newWord'):
            session.words.append(cgi.escape(self.request.get('newWord')))
        session.put()

        json_to_send = {'username': session.name, 'words': session.words}

        self.response.headers['Content-Type'] = 'application/json'
        self.response.out.write(json.dumps(json_to_send))


app = webapp2.WSGIApplication([('/', MainPage), ('/data', JsonData)],
                              debug=True,
                              config=config)