djangogoogle-app-enginerpxnow

Set a "global pre-request variable" in Django in Middleware


I'm trying to combine Google App Engine with RPX Now user authentication and a per-user limited access pattern.

The per user access-limiting pattern relies upon GAE's global User.get_current_user(), like-so:

from google.appengine.api import users

class CurrentUserProperty(db.UserProperty):
  def checkCurrentUser(self, value):
    if value != users.get_current_user():
      raise db.BadValueError(
          'Property %s must be the current user' % self.name)
    return value

  def __init__(self, verbose_name=None, name=None):
    super(CurrentUserProperty, self).__init__(
        verbose_name, name, required=True, 
        validator=self.checkCurrentUser)

However, with GAE Utilities' sessions storing RPX's user identifier, there is no global User.

The most obvious solution to me is to create some global User variable (somehow localized to the current request/thread) in the middleware. However, I wouldn't do this unless I was confident there were no race conditions.

Is there any way to get the identity of the current user (as stored in the request session variable) to the CurrentUserProperty when CurrentUserProperty is constructed?

Thank you for reading.

EDIT:

Reading GAE's google/appengine/tools/dev_appserver.py:578 which does a:

579 env['USER_ID'] = user_id

and google/appengine/api/users.py:92ff which reads:

92  if _user_id is None and 'USER_ID' in os.environ:
93     _user_id = os.environ['USER_ID']

seems to suggest that you can safely set the environment in a single Google App Engine request (but I may be wrong!).

Presumably, then, I can set an environment variable in middleware. It smells of trouble, so I'd like to know if anyone else has (similarly) tackled this.


Solution

  • App Engine instances (and indeed, CGI in general) are guaranteed to be single-threaded, so setting an environment variable per request is indeed safe - in fact, all the information about the current request is passed in through the current environment! Just make sure that you _un_set the environment variable if the user is not logged in, so you can't have an unauthenticated request get the authentication of the previous request to hit the same instance.