問題を説明させてください:
Pyramidを介して静的アセットを提供しています:
config.add_static_view(name='static', path='/var/www/static')
そしてそれはうまくいきます。
これで、データベースにセッションを作成するカスタムセッションファクトリができました。ブラウザがセッションCookieを提示しているかどうかをチェックします。含まれている場合は、DBからセッションを検索します。そうでない場合は、DBに新しいセッションが作成され、Cookieがブラウザに返されます。
ここまでは順調ですね。
これで、(ホームページを生成する)内部ではhome_view
、リクエスト変数にアクセスしません。
@view_config(route_name='home', renderer="package:templates/home.mak")
def home_view(request):
return {}
このため、ユーザーがホームページにアクセスすると、サーバー上にセッションが作成されません。これは、Pyramidがアクセスしたときにのみセッションを怠惰request.session
に作成するためだと思います。したがって、ホームページ要求の応答ヘッダーには、Set-Cookie
セッションのヘッダーは含まれていません。
ホームページのmakoテンプレート内で、JavaScriptファイルとCSSファイルの静的URLを生成しています...
<link rel="stylesheet" href="${request.static_url(...)}"
<script src="${request.static_url(...)}"></script>
現在、私はPyramidから静的アセットを提供しているため、これらのアセットに対するすべてのリクエストはPyramidの機械全体を通過します。
つまり、ブラウザが静的アセットをフェッチするリクエストを送信すると、Pyramidが何らかの方法でセッションを作成します。つまり、Pyramidはデータベースにセッションを作成し、ブラウザが静的アセットのリクエストを送信したときにセッションCookieを送り返します。これが問題1です。
ブラウザは、静的アセットに対するすべてのリクエストを並行して送信します。FirefoxとChromeの最近のバージョンを使用しています。実際のHTMLドキュメントのHTTPリクエストはヘッダーを返さなかったSet-Cookie
ため、静的アセットのリクエストにはCookieヘッダーがありません。これが意味するのは、Pyramidはどのリクエストに対してもセッションCookieを認識せず、静的アセットに対して取得するリクエストごとにデータベースに新しいセッションを作成することです。
ホームページで7つの静的アセットをフェッチしている場合、7つのセッションエントリが作成されます。これは、これらすべてのリクエストがサーバーと並行して行われ、セッションCookieがないため、Pyramidがそれぞれのセッションを作成するためです。
ホームページリクエストの一部として意図的にセッションにアクセスした場合、この問題は発生しません。DBにセッションを作成し、ブラウザにCookieを送信します。ブラウザは、サーバーから要求する静的アセットごとに(並行して)Cookieを送り返します。
@view_config(route_name='home', renderer="package:templates/home.mak")
def home_view(request):
if request.session: pass
return {}
静的アセットリクエストでのセッションの作成を防ぐにはどうすればよいですか。さらに良いことに、静的アセットのリクエストを受け取ったときにPyramidがセッションファクトリに触れないようにしたいのですが、これは可能ですか?
次に、Pyramidが静的リクエストで新しいセッションを作成する理由がわかりません。
アップデート
これがセッションファクトリーです。
def DBSessionFactory(
secret,
cookie_name="sess",
cookie_max_age=None,
cookie_path='/',
cookie_domain=None,
cookie_secure=False,
cookie_httponly=False,
cookie_on_exception=True
):
# this is the collable that will be called on every request
# and will be passed the request
def factory(request):
cookieval = request.cookies.get(cookie_name)
session_id = None
session = None
# try getting a possible session id from the cookie
if cookieval is not None:
try:
session_id = signed_deserialize(cookieval, secret)
except ValueError:
pass
# if we found a session id from the cookie
# we try loading the session
if session_id is not None:
# _load_session will return an object that implements
# the partial dict interface (not complete, just the basics)
session = _load_session(session_id)
# if no session id from cookie or no session found
# for the id in the database, create new
if session_id is None or session is None:
session = _create_session()
def set_cookie(response):
exc = getattr(request, 'exception', None)
if exc is not None and cookie_on_exception == False:
return
cookieval = signed_serialize(session.session_id, secret)
response.set_cookie(
cookie_name,
value=cookieval,
max_age = cookie_max_age,
path = cookie_path,
domain = cookie_domain,
secure = cookie_secure,
httponly = cookie_httponly,
)
def delete_cookie(response):
response.delete_cookie(
cookie_name,
path = cookie_path,
domain = cookie_domain,
)
def callback(request, response):
if session.destroyed:
_purge_session(session)
delete_cookie(response)
return
if session.new:
set_cookie(response)
# this updates any changes to the session
_update_session(session)
# at the end of request
request.add_response_callback(callback)
# return the session from a call to the factory
return session
# return from session factory
return factory
その後、
factory = DBSessionFactory('secret')
config.set_session_factory(factory)
アップデート
私のカスタム認証:
class RootFactory:
__acl__ = [
(Allow, Authenticated, 'edit'),
# only allow non authenticated users to login
(Deny, Authenticated, 'login'),
(Allow, Everyone, 'login'),
]
def __init__(self, request):
self.request = request
class SessionAuthenticationPolicy(CallbackAuthenticationPolicy):
def __init__(self, callback=None, debug=False):
self.callback = callback
self.debug = debug
def remember(self, request, principal, **kw):
return []
def forget(self, request):
return []
def unauthenticated_userid(self, request):
if request.session.loggedin:
return request.session.userid
else:
return None
その後、
config.set_root_factory(RootFactory)
config.set_authentication_policy(SessionAuthenticationPolicy())
config.set_authorization_policy(ACLAuthorizationPolicy())