Resource as Avatar (was Re: [Twisted-web] newbiew question)
exarkun at divmod.com
Wed Jul 23 10:58:09 EDT 2008
On Wed, 23 Jul 2008 15:13:49 +0100, Phil Mayers <p.mayers at imperial.ac.uk> wrote:
>>>The information about the user does not belong in any Resource subclass: a
>>>Resource is a page that can be generated for different users, so it should
>>>only contain information that is the same for all users. Any user specific
>>>data should be fetched via the request object.
>>This is totally inaccurate. It's perfectly reasonable to store
>>user-specific data in Resource objects. "a Resource is a page that
>>can be generated for different users" is either irrelevant or not
>>true, I can't tell which. You can dynamically and return Resources
>>based on which user is making the request.
>>Now, I'm not sure my favorite abstraction for a user is a string; I'd
>>probably pass something other than a username to a Resource. Perhaps a
>>rich object representing the user.
>Since this is a common mis-conception (one I suffered from and have now
>disabused myself of) it's worth discussing.
>If my understanding is correct: twisted.cred uses the concept of an
>"avatar". Avatars (I think...):
> * are protocol objects
In some sense, they are protocol objects - they are used by protocol
implementations to authorize user actions. They are not /themselves/
protocol implementations, though - that is, they do not implement
IProtocol (at least, not in general) or subclass Protocol. I'm not
sure if this is what you meant.
> * represent the user
Yep, absolutely. :)
>In twisted.web, the Resource *is* the avatar. In twisted.mail.imap, the
>Mailbox is the avatar. In twisted.conch, the Shell is the avatar (and so
>I found this initially confusing, because in many web frameworks e.g. Zope,
>where I came from, the objects representing resources are:
> * long lived
> * the same instances serve >1 HTTP request
> * instantiated at process start time
>It's also somewhat confusing because unlike other protocols, HTTP requests
>are very short-lived. It's worth noting you *can* have long-lived multi-
>instance t.w.Resource objects.
>In twisted, a common design pattern seems to be (I hope; I adopted it...)
> * have your realm return a root Resource i.e. one for "/"
Yep, although note that it doesn't _have_ to be "/". You can have the
authenticated/authorized part of your resource hierarchy start wherever
you like. If it starts at "/", then every resource on the server is
> * attach your User object to that resource
> * have your root resource dynamically create the leaf resources via
>locateChild or childFactory, then attach the User object
> * when you need user info, get at it via e.g. self.user
> * let the leaf/root objects get GC-ed when the HTTP request is done
>I believe changes have been committed to twisted.web making this design
>pattern even more preferred:
>Code which, by the way, I very much like the look of.
>Could someone clarify if this is the "right" way of doing things?
Sounds like you're basically on target. One area that you didn't talk
much about is what the role of the user object is. It's possible to
just examine the user object and then, in your custom Resource, decide
what to do based on that examination. A more powerful approach is to
actually delegate those decisions to the user object (and this is why
twisted.web.guard makes the user object a Resource). This removes all
checking from your code and just makes the right code for each user
execute automatically. Explicit checking is tedious and error prone.
Delegating all authorization decisions to the avatar simplifies the
code and makes it less likely that you'll introduce a security issue.
More information about the Twisted-web