Note
セッションコードは大幅な書き直しが必要です。それはキャッシングにお いてより一般的な使用パターン (たまにしかないアップデート/頻繁な読み 取り) に最適化された Beaker の Caching コンテナ API を使用していま す。キャッシュとは異なり、セッションは一度だけロードされ、そして一 度だけ保存されます。そして同じセッションに対して複数の書き込みが同 時に起こることはめったにありません。そのため、現在のキャッシュイン タフェースが行う過剰な、しかし必要なロックは、セッションに関しては 単なる性能の浪費です。
このセッションプロキシ/遅延作成オブジェクトは、本物のセッションオブジェ クトへのアクセスを処理します。セッションがそれまでに使用されたことがな ければ、セッションオブジェクトは自動的に作成されてセットアップされます。 本物のセッションオブジェクトへのアクセスを扱うのにこのようなやり方でプ ロキシを使用するのは、リクエストの間にセッションが実際に使用されない場 合に、セッションを作成して永続的なストレージからロードするのを避けるた めです。
純粋なクッキーベースのセッション。クッキーベースのセッションを使用する 際に認識されるオプションは、一般的なセッションよりわずかに制限されてい ます。
key
クッキーにセットされる名前。
timeout
セッションデータがどの程度の期間有効とみなすか。これはクッキーが存 在しているかどうかにかかわらず、セッションデータがまだ有効であるか どうかを決定するために使用されます。
encrypt_key
セッション暗号化のために使用するキー。指定しなければセッションは暗 号化されません。
validate_key
暗号化されたセッションに署名するために使用されるキー。
cookie_domain
クッキーに使用するドメイン。
secure
クッキーが SSL を通じてのみ送られるかどうか。
beaker.session.key = wiki
beaker.session.secret = ${app_instance_secret}
Pylons にはキャッシュミドルウェアが有効な状態で付属しています。それはセッ ションの取り扱いを提供するのと同じパッケージである Beaker の一部です。 Beaker はいくつかの異なる種 類のキャッシュバックエンドをサポートします: メモリ, ファイルシステム, memcached, そしてデータベースです。サポートされるデータベースパッケージ は、 SQLite, SQLAlchemy, および Google BigTable です。
Beaker のキャッシュとセッションオプションは辞書で構成されます。
Note
Paste パッケージと共に使用する場合、 Beaker が自身のオプションと他 のアプリケーションの設定オプションを区別できるように、すべての Beaker オプションは beaker. プリフィックスをつけるべきです。
設定オプションは session. または cache. プリフィックスをつける べきです。
Accepts: string Default: None
キャッシュデータが保存されるデータディレクトリ。この引数が存在していな いなら、通常の data_dir パラメータに ”./sessions” を追加したものが 使用されます。
Accepts: string Default: dbm
セッションに使用されるストレージのタイプ。現在のタイプは “dbm”, “file”, “memcached”, “database”, および “memory” です。ストレージはキャッ シュシステムも使用する Container API を使用します。
dbm ファイルを使用する場合、各ユーザのセッションは beaker.container.DBMNamespaceManager クラスを通してそれぞれ別 の dbm ファイルに保存されます。
‘database’ または ‘memcached’ を使用する場合、以下の対応するセクション で文書化されるように、追加の設定オプションが必要です。
セッションオンリーには、 “cookie” タイプの追加選択があります。 それはセッションに “secret” オプションが設定されることを必要とします。
タイプが ‘database’ にセットされているとき、以下の追加オプションを使用 できます。
Accepts: string (SQLAlchemy db uri と同じ書式) Default: None
SQLAlchemy がデータベースに対して使用する書式と同様のデータベース URI 。 データベースのための適切なデータベースパッケージもインストールしなけれ ばなりません。
Accepts: boolean Default: False
楽観的なセッションロックを使用します。この場合、キャッシュ値をアップデー トするときに、バージョン番号を比較するために select が行われることに注 意してください。
Accepts: dict Default: None
SQLAlchemy のエンジンに直接渡される値の辞書。これは SQLAlchemy 0.3 に対 してのみ適切であることに注意してください。
Accepts: 有効な SQLAlchemy 0.4 データベースオプション Default: None
SQLAlchemy 0.4 以上を使用するとき、プリフィックスに sa. を持つすべ てのオプションが SQLAlchemyデータベースエンジンに渡されます。 一般的な パラメータは pool_size, pool_recycle などです。
Accepts: string Default: None
url は memcached のための 単一の IP アドレスか、セミコロンで区切られた IP アドレスのリストです。
Beaker は memcached と通信するのに py-memcached または cmemcache のどち らかを使用できますが、 cmemcache は memcached に接続できなくなったとき に Python を segfault させることがあることに注意してください。
Accepts: boolean, datetime, timedelta Default: True
セッションクッキーの有効期限。デフォルトは “True” で、有効期限を設定し ません (ブラウザが閉じられたときにクッキーの期限が切れます)。 “False” 値は無期限を意味します (datetime オブジェクトに格納できる最大の日時を指 定して、それを使用します)。この値は現在時刻に加算される datetime.timedelta() オブジェクトまたは datetime.datetime() オ ブジェクトにすることもできます。
Accepts: string Default: The entire domain name being used, including sub-domain, etc.
デフォルトでは Beaker のセッションはクッキードメインとして完全なホスト 名が設定されます。サブドメインにおいてはこの値をクッキーを有効にしたい トップドメインに設定する必要があります。
Accepts: string Default: None
このセッションのためのセッション id。 クッキーとともにセッションを使用 する場合、セッションはリクエストから自動的に値を作成、保存、取得するの で、このパラメータは必要ありません。セッションに URL ベースの方法を使用 する場合、セッションが最初に作成されるときに id は id データメンバーか ら取得され、次に新しい URL を出力する際に使用されます。
Accepts: string Default: beaker_session_id
セッションを特定するためにクッキーのキーとして使用されるキー。これを変 えることで、いくつかの異なったアプリケーションが同じホスト名の下で異な るセッションを持つことができます。
Accepts: string Default: None
暗号化セッション id を有効にする秘密鍵。 None でないときに、セッション id はこの値に対して作成された MD5 署名で生成されます。
“cookie” セッションタイプで使用されると、 secret はクッキーの内容を暗号 化するために使用されます。十分にセキュアな、少なくとも 54 文字以上のラ ンダムに生成された文字列にすべきです。
Accepts: integer Default: None
セッションがタイムアウトするまでの秒数。セッションが timeout 秒以上ロー ドされなかった場合、タイムアウトが起こります。
カスタムミドルウェアをどのレイヤーに置くかを決める際には注意が必要です。 多くの場合、ミドルウェアは Pylons WSGI アプリケーションインスタンスと Routes ミドルウェアの間に置かれるべきです。しかし、ミドルウェアがセッショ ンオブジェクトやルーティングが扱われるより 前で 実行する必要があるな ら:
# Routing/Session/Cache Middleware
app = RoutesMiddleware(app, config['routes.map'])
app = SessionMiddleware(app, config)
# MyMiddleware can only see the cache object, nothing *above* here
app = MyMiddleware(app)
app = CacheMiddleware(app, config)
Session, Routes, Cache ミドルウェアなどのいくつかの Pylons ミドルウェア層は、単に environ 辞書にオブジェクトを加えるか、またはレ スポンスに HTTP ヘッダを加えるだけです (例えば Session ミドルウェアはセッ ションクッキーヘッダーを加えます)。一方、 Status Code Redirect や Error Handler は、リクエスト全体を完全に横取りして、そのレスポンス を変えるかもしれません。
Session のための db スキーマは、各セッションについて「最後にアクセスさ れた時間」を格納します。これによって、簡単な SQL コマンドを使用すること で期限切れのセッションの bulk 削除が可能になります。 SQL コマンドは毎日 実行され、「最後にアクセスされた」タイムスタンプが 2 日より前 (あるいは その他の任意の条件で) 期限切れのセッションをクリアします。
コントローラで使用される言語を動的に (on the fly) 設定する方法。
例えばこれを使えば、ユーザがアプリケーションをどの言語で動かしたいか 設定できるようになります。セッションオブジェクトに値を保存してください:
session['lang'] = 'en'
session.save()
そうすると、各コントローラが呼び出された時にコントローラの __before__() メソッドでセッションから言語を読み込んで設定することに よって、継続して設定された言語でページが表示されるようになります。
def __before__(self):
if 'lang' in session:
set_lang(session['lang'])
権限トークンはクライアントのセッションに格納されます。そして、ウェブア プリは、送信されたリクエストの権限トークンをクライアントのセッションに 保存された値に対して検証することができます。
これはリクエストが originating ページから来たことを保証します。 クロス サイト・リクエスト・フォージュリ に関して詳しい情報は wikipedia のエ ントリーを見てください。
Pylons はコントローラに代わってこの検証を行う authenticate_form デ コレータを提供しています。
これらの helpers は Pylons の session オブジェクトに依存しています。 それらの大部分は、 API 呼び出しを変えることによって容易に別のフレームワー クに移植できるでしょう。
(From a paste #441 baked by Ben Bangert)
dev.ini ファイルでセッションにクッキーを使用しないように設定してください。
beaker.session.use_cookies = False
そしてコントローラアクションの中で mode d’emploi (使用法、取扱説明書) としてこのようにします:
from beaker.session import Session as BeakerSession
# Get the actual session object through the global proxy
real_session = session._get_current_obj()
# Duplicate the session init options to avoid screwing up other sessions in
# other threads
params = real_session.__dict__['_params']
# Now set the id param used to make a session to our session maker,
# if id is None, a new id will be made automatically
params['id'] = find_id_func()
real_session.__dict__['_sess'] = BeakerSession({}, **params)
# Now we can use the session as usual
session['fred'] = 42
session.save()
# At the end, we need to see if the session was used and handle its id
if session.is_new:
# do something with session.id to make sure its around next time
pass
呼び出された WSGI アプリケーションが共通のセッション管理ユーティリティ を共有するのを許可する方法。
(From a paste #616 baked by Mark Luffel)
# Here's an example of configuring multiple apps to use a common
# middleware filter
# The [app:home] section is a standard pylons app
# The ``/servicebroker`` and ``/proxy`` apps both want to be able
# to use the same session management
[server:main]
use = egg:Paste#http
host = 0.0.0.0
port = 5000
[filter-app:main]
use = egg:Beaker#beaker_session
next = sessioned
beaker.session.key = my_project_key
beaker.session.secret = i_wear_two_layers_of_socks
[composite:sessioned]
use = egg:Paste#urlmap
/ = home
/servicebroker = servicebroker
/proxy = cross_domain_proxy
[app:servicebroker]
use = egg:Appcelerator#service_broker
[app:cross_domain_proxy]
use = egg:Appcelerator#cross_domain_proxy
[app:home]
use = egg:my_project
full_stack = true
cache_dir = %(here)s/data
pylons-discuss Google グループの議論から:
> I wouldn't expect a SA object to be serializable. It just doesn't
> make sense to me. I don't even want to think about complications with
> the database and ACID, nor do I want to consider the scalability
> concerns (the SA object should be tied to a particular SA session,
> right?).
(直訳)
私は SA オブジェクトがシリアライズ可能とは思っていません。それは単
に私には理解できません。私はデータベースと ACID の複雑さについて考
えたくありませんし、スケーラビリティについても関心を持ちたくありま
せん。 (SA オブジェクトは特定の SA セッションに結びつけられるべきで
すよね?)
SA オブジェクトはシリアライズ可能です。 (assign_mapper() を使って いない場合。それは __getstate__() を定義しないと物事を複雑にします)
上記のエラーは entity が元のセッションから detach されていないことが原 因です。シリアライズする際は、オブジェクトを手動で適切なセッションの間 を往復させなければなりません。
シリアライズしたオブジェクトを SA Session に戻すには、以下の 3 通りの方 法があります:
__getstate__() を持っているマップされたクラスは desired プロパ ティだけをコピーして、SA セッションポインタをコピーしません。
beaker.put(key, obj) ... obj = beaker.get(key) Session.add(obj)
通常の古いマップされたクラス。 expunge() ステップを加えてください。
Session.expunge(obj) beaker.put(key, obj) ... obj = beaker.get(key) Session.add(obj)
オリジナルのオブジェクトについては __getstate__() や expunge() について気にする必要はありません。 merge() を 使用してください。これは上で示した expunge() メソッドよりクリー ンな方法ですが、通常はデータベースからオブジェクトをロードすることを 強制するので、必ずしも「効率的」ではないかもしれません。またそれは与 えられたオブジェクトの状態を対象のオブジェクトにコピーしますが、これ は間違いの元かもしれません。
beaker.put(key, obj) ... obj = beaker.get(key) obj = Session.merge(obj)