Message info
 
To:django-developers@googlegroups.com From:Joe Tennies Subject:Re: auth.User refactor: reboot Date:Sun, 18 Mar 2012 11:00:38 -0500
 

A feature I would love to see is the ability to support multiple forms of authentication for a single user account. (One account to many credentials.)

On Sat, Mar 17, 2012 at 11:19 PM, Ian Lewis <ianmlewis@gmail.com> wrote:
Hi,

On Sun, Mar 18, 2012 at 9:41 AM, Russell Keith-Magee
<russell@keith-magee.com> wrote:
>> 1. Django shouldn't decide what fields go on the user model. The app
>> provides an abstract base class which developers subclass to add the
>> appropriate fields they need.
>
> +1

THX

>> 2. Django shouldn't decide the type of the primary key. The app only
>> relies on the fact that the object has a pk. The id field can be named
>> anything you wish and can be any type (integer, char, uuid, etc.).
>
> +1

THX again

>> 3. Third party apps don't rely on the user having any fields but
>> rather the base user class defines methods that are implemented by
>> subclasses. Methods like get_display_name() which provides a way for
>> third party apps to get something to display.
>> 4. Rather than provide mixins or something, we should have conventions
>> for the field names like 'email' and third party apps should check if
>> the user has one using duck typing e.g. hasattr(user, 'email'). An
>> alternative could be to provide some kind of API for commonly used
>> actions like emailing users.
>
> This is essentially all I was proposing when I spoke of an "admin User contract"; that we define some basic "identity" functions that every User object is expected to provide -- short name, long name, and so on.
>
> The admin case is a little more complicated because there is also a required API for permissions and groups, but to my mind, these are different contracts, and should be documented as such.

My solution is simply authentication, authorization would need to be
added on or in a separate app built on top of newauth.

>> 5. Basic username (or email)/password authentication can be provided.
>> The app has a base user class from which a basic abstract user with
>> username/password is defined. This can implement setting passwords
>> properly and provide forms etc.
>> 6. Multiple user models can be defined (Like say for normal users and
>> affiliate users or admin users). If one wants to create a project
>> currently with a separate user model, none of the machinery in the
>> auth app can be used.
>
> Sure you can -- you have a base User, and then subclasses to get AdminUser and NormalUser -- both of which are effectively just another type of UserProfile.

I meant one that was a completely separate concrete base model. The
current auth forces you to take along with you all the fields on the
User model.

>> You create users by creating your own app in your project and creating
>> a User there:
>>
>> account/models.py
>>
>> from django.db import models
>>
>> from newauth.models import UserBase
>>
>> class User(BaseUser):
>> full_name = models.CharField(u"Full Name", max_length=255)
>> email = models.EmailField('Email Address')
>> profile = models.TextField('Profile Bio', blank=True, null=True)
>> avatar = models.ImageField('Avatar', upload_to='profileimg/',
>> blank=True, null=True)
>>
>> def get_display_name(self):
>> return self.full_name
>>
>> class Meta:
>> db_table = 'my_user_table'
>> verbose_name = u"Djangonaut"
>> verbose_name_plural = u"Djangonaut"
>>
>> There are even docs and tests.
>
> How does this address the issue of reusable apps referencing User? Let's say I write a comments app, and want an Author field. I need a ForeignKey to "User". But I can't have a foreign key to BaseUser, because it's an abstract class. How do I define my Comment model in such a way that it can reference a generic "User"?
>
> It seems to me that the solution you're proposing requires the LazyFK and app-refactor infrastructure I've described in order to be useful in the general case (not that I'm complaining, mind -- just pointing out that our two proposals are complementary :-).

This is a bad example for showing how that works. I just wanted to
illustrate how you would make your own User model. In the case where
you want a foreign key to User you can import the default user model
from newauth.models as User much like you do with the current django
auth app.

See: http://ianlewis.bitbucket.org/django-newauth/third_party.html

>> This is going to be the biggest problem with my solution. There would
>> probably have to be some kind of compatibility layer added to make
>> existing apps work or to provide a simpler migration path.
>
> Isn't the compatibility layer just an implementation of the existing auth.User class that extends from BaseUser? We're going to have to ship this user class anyway, so that everything works out of the box; then if anyone wants to define their own User class, they can.

Perhaps. I think in reality it will be a bit more complicated though I
haven't really thought about it. I didn't really consider
authorization or backwards compatibility as a goal of the project when
first writing it.

>>> * It solves the immediate problem ...
>>>
>>> As I see it, the immediate problem is that developers want to be able to modify the base requirements of auth.User. There may well be people who want to completely change contrib.auth, but for the moment, the 90% case can be solved by modifying max_length or setting unique=True on the email field, and/or removing the username field. The rest of auth.User is fine, at least for now.
>>
>> I agree this is the most immediate problem. If you could do this it
>> would be ok though I have other issues with auth that prevent me from
>> using it so even if I could modify the fields on auth.User I still
>> won't use it.
>
> I'm not completely convinced that your proposal isn't just the "long term refactor" of auth that I referred to. I've only had a quick look at your code, but it seems to share a lot of similarities with oldauth. Yes, there have been modifications to remove dependencies on certain attributes of User, but from my quick check, I didn't see anything that we couldn't achieve through a process of modification of the existing code (if we didn't have an existing pret-a-porter implementation like yours)

That's perhaps true. I suppose the primary key thing and being able to
separate admin and regular users were the things I personally wanted
the most.

>> There isn't much you need on a user object besides a primary key and
>> maybe a way to authenticate it. Everything else is profile so things
>> like the name, email, etc. are all profile. I just don't really see
>> the benefit of breaking all this up and requiring you to do multiple
>> lookups in every view or make a middleware that goes and gets the
>> profile object for you. It's terribly inconvenient. On top of that the
>> difference between a user and a profile isn't really all that clear
>> in a lot of apps. I think if you need or want this kind of topology
>> you can create it yourself in your project.
>
> Yes, all that is strictly needed is a PK and a way to authenticate -- but in practice, a user object isn't much use unless you can say "Hello <user>", so I don't see why basic identity mechanisms shouldn't be part of the basic User contract (not necessarily defined at a data level, just at a data access level).

Sure. That's kind of why I defined an method for getting how to
display the user's name. I think that when you say "but in practice, a
user object isn't much use unless you can say "Hello <user>"", you are
really saying that the user isn't much without the profile data. It's
a very short step from wanting to display the user's name to wanting
to display his email or something else.

> Personally, I don't have a problem with UserProfile as a pattern, especially when it comes to per-app settings. However, the good news is that both approaches are possible once the User model is configurable. We can describe the approach of a generic User with UserProfile objects containing app settings; and also document the fact that if you have performance (or taste/convenience) concerns about the joins to a UserProfile object, you can define a per-project User object that incorporates all the profile data you want.

Yes. That's what I thought as well. There isn't stopping you from
using the user profile approach or even defining multiple profiles.

Thanks for taking a look at it,
Ian

--
Ian

http://www.ianlewis.org/

--
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+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.




--
Joe Tennies
tennies@gmail.com

--
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+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.