On Monday, April 2, 2012 at 10:56 PM, Alex Ogier wrote: > I realize that arguing with a BDFL might get me nowhere, but I don't think > that multi-profile + select_related + proxy attributes on the user model is > the proper approach for users going forward. The proposal makes some basic > sense as an incremental improvement on the current status quo of a built-in > user with fixed 30-character identifier and single one-to-one profile. But in > the larger scheme of things it moves further in the wrong direction, in my > opinion, towards a model that addresses people's specific 80% questions > (email-as-identifier, packageable extra fields) but not the general > best-of-all-worlds mechanisms. > > Consider the other batteries-included frameworks out there. I think the three > biggest ones are probably Ruby on Rails, ASP.NET (http://ASP.NET) MVC, and > Play Framework. Something all three have in common, something I think would > be valuable for Django, is that their User identity is absent, and > authentication and authorization modules are added to a developer-created > User model ad-hoc. I think it's fair to say, the ecosystem of third-party > authentication mechanisms surrounding all three of these competitor > frameworks is MUCH healthier than Django's, for the simple reason that it is > much more flexible and sane to define your own user and plug in an > authentication module then it is to plug authentication into a fixed user > model that magically proxies back (even one as simple as a varchar identity + > password). > > The basic idea is that "authentication" is something that can be provided for > any model you like. When a user authenticates, they are providing some sort > of authentication token to your project that proves they are who they say > they are, and as a developer you are free to attach this authentication token > to *whatever you like,* not only contrib.auth.models.User. There is a rich > ecosystem of third party authentication apps for our competitor frameworks > that all work on this principle. They can provide authentication flows that > bounce the user back and forth to twitter.com (http://twitter.com), their > oauth provider, browserid, etc. and it is precisely because they don't demand > anything from a central object. Even something as simple as "all > user.identifiers that start with 'oauth2$' belong to our auth mechanism" > starts to open all sorts of security holes. What if someone wants to > authenticate by email+password OR by third party proof of email ownership (my > university has a mechanism like this)? Well, if someone can manage to register an account belonging to 'aog...@princeton.edu (mailto:aog...@princeton.edu)', maybe by triggering some obscure email change recovery form wizard or something, then suddenly they possess my account on Django. > > This is why I think the only sane long-term solution involves distinct and > pluggable authentication modules, and a concept of users that doesn't enforce > any brand of identity. The second stipulation is very important for social > reasons, if only to ensure that the path of least resistance for third-party > authentication doesn't involve trying to overload identity mechanisms for > disparate and incompatible purposes. > > JKM, you seem concerned that the notion of pluggable Users by necessity > involves magical settings. > > > I'm convinced that such an idea is ultimately a bad idea: it allows apps > > exert action at a distance over other apps. It would allow the idea of a > > user to completely change without any warning simply by modifying a setting. > > I am not convinced that this must be so. Asking a developer to write their > own User model is not the same thing as automagically reshaping > contrib.auth.models.User based on settings. A developer-defined notion of > identity is a thing that should be codified in software by constructing a > model. This community seems fixed on the idea that whatever model the > developer comes up with to satisfy the bizarre constraints of his particular > website, it must eventually be mounted at auth.User lest the world come > crashing down as foreign keys break, middleware throws exceptions and > California slides into the pacific ocean. > > Nearly every other framework out there does this the opposite way: to > authenticate with a third-party service, you add fields to your identity > model to support whatever credentials are necessary. Not the other way round, > where auth modules define models that have OneToOneFields to auth.User that > uses an AUTH_PROFILES setting to magically proxy back. > > I get that Django's core is very accustomed to the relational database mode > of thinking: "If a User might own a Twitter handle, then let's create a table > of twitter handles in the twitter-auth app, and foreign key back to the > default User model". It's really not that bad to go the other way for a > moment, and say "If a User might own a Twitter handle, then let's add a > twitter_handle field to Users." The reason being that the latter is *so much > more flexible*. You can simulate the first with the second, but not vice > versa. Twitter-auth might not need its own table (in fact, it shouldn't need > its own table). If you really wanted to, you could make one, and foreign-key > *from* the user model which gives you everything the first solution has, with > no need to created magical .prof1, .prof2 proxy attributes. You could even > let users sign in with multiple handles with a many-to-many. Heck, maybe your > blog posts have their own twitter credentials, I don't know. > > So here's the short version of my proposal, which I plan on writing up in > full tomorrow: Break auth as it stands into reusable pieces. Let people write > their own user models, optionally using those pieces. Provide straightforward > settings for any contrib apps that absolutely *must* have a specific model to > key on (ideally none, but comments and admin probably need shims). Document > the new wave of best practices, borrowed straight from the frameworks that > got this right from the start: Write your own user, decide what identity > means (and hence, what your login forms look like), add in whatever > authentication mechanisms you like, add in whatever authorization mechanisms > you need (with specific instructions on what contrib.admin demands from your > model), and run with that. > > Sorry for the rant, hopefully I'm not burning too many bridges, > Alex Ogier > > -- > You received this message because you are subscribed to the Google Groups > "Django developers" group. > To post to this group, send email to django-developers@googlegroups.com > (mailto:django-developers@googlegroups.com). > To unsubscribe from this group, send email to > django-developers+unsubscr...@googlegroups.com > (mailto:django-developers+unsubscr...@googlegroups.com). > For more options, visit this group at > http://groups.google.com/group/django-developers?hl=en. Identity doesn't have anything to do with automatically dispatching users. All it is is a unique identifier. That's all this proposal honestly enforces that your users have. Some single piece of identifiable data that can be used to differentiate. This could be a username, or an email address. It could be a random string. Anything you want.
In your example you might have a TwitterProfile that provides 2 fields, "authenticated_by_twitter" and "twitter username". Then if you want to check how a person authenticated to your site, you'd merely check if user.data["authenticated_by_twitter"] was True. The identifier doesn't need to have that data codified in it, (but it could!) and I honestly do not think the statement "all users must have 1 single string of any length that uniquely identifies them" is that big of a burden. -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.