> My application has to authenticate a user, determine which group > (singular) they belong to, then enforce group permissions. (I'm > vaguely thinking of Zope's roles.) The permissions range from including > certain fields in the display to accessing update screens. However, the > anonymous user can also do searches and get limited displays without > logging in. Management wants people to be able to log in at any point > and continue their search-in-progress with upgraded permissions. This > implies a login link on every page, which goes to a login form, then > back to the previous page, now displaying more fields or records. This is sort of what my webmail app does. _q_access does 3 things: if your query string has magic __passwd and __login fields, it makes a new session for you and lets you go; if you're logged in, it lets you go; otherwise, it throws Not_logged_in. _q_exception_handler snags Not_logged_in and returns the login page. The login page packs up the query string in hidden fields and adds __passwd and __login fields, setting the action target to wherever you really wanted to go before the login machinery snagged you. BTW, my webmail app also uses multiple threads, if you want to see how it could be done. But unless you want a lot of shared state between processes (like a shared cache), then you're probably better off with the multiple process SCGI model. FastCGI also does multiple processes automatically, but it's more complicated than SCGI. > Alternatives seem to be a custom Publisher subclass, calling an > authenticate() function at the beginning of every "servlet" function > (undesirable), or making all "servlets" be a subclass of an > AuthenticatedPage class (also undesirable because I'd lose Quixote's I don't see how this is much different from writing _q_access for a root-like object. > My user scheme is like this. > > # User logs in, anddetermines which group they're in. > === user.py > class User: > def __init__(self, username, group): > self.username = username > self.group = group > self.canViewSensitiveData = > self.canUpdate = > self.can... Maybe a Group object whose instances are like tokens? More powerful groups are subclasses, so each page (or each pages _q_access) can have a require_group(request.session, Some_group) that does any(lambda g: isinstance(g, Some_group), session.user.groups)