The underlying problem of today's auth.User is IMO that it conflates
two things: authentication and a hook for authorization/ownership.
For the former, there are a zillion and growing ways to authenticate:
OpenID, OpenAuth, Federated with Shibboleth or SAML, YubiKey, good old
HTTP-password straight on the server (RemoteBackend), local user and
password (Backend), etc, etc. etc. They can't all be smudged together
in a single table, so let's decouple things.
The absolutely minimum User-model looks like this:
class MinimalUser(models.Model):
pass
There's nothing wrong with your eyes. That's a model containing just a
primary key. Authentication-specific models could then be:
class SomeAuthUser(models.Model):
user = models.OneToOneField(MinimalUser)
... auth-specific fields
All other models that have been edited by/owned by someone is as usual:
class MyBlogEntry(models.Model):
edited_by = models.ForeignKey(MinimalUser)
... other fields
We already have a way of specifying a default profile, that's where
we'd put first name, last name, favorite pet, whatever. Since neither
first_name nor last_name is mandated anywhere, even Madonna and Prince
can use the site, with no hacks.
You might think that we *must* have a username in MinimalUser. But
what a username looks like is frequently determined by the
authentication-method, we can't validate for that in MinimalUser. A
minimal username would wind up being a CharField(max_length=255). One
user can also have several usernames, depending on the
authentication-method used. What *would* be useful in the MinimalUser
is a "display name", the user's preferred name/pseudonym to be shown
to others, in full glorious high-plane unicode if needed.
As for an email-address: "You want my email-address? Which one? I log
in with openid and you want my email-address? But I'm already verified
by the provider?! Is that *really* why you want my email-address? Ah,
I thought so, you're harvesting good addys. No thanks, I'll use this
other site instead." If you do need email-addresses, do as in
django-email-confirmation: allow more than one. Decouple. Don't put it
directly on the user. Don't make the user depend solely on an
email-address: what happens if the user switches from, say, gmail, to
hot-mailer-of-the-day.com?
Date-joined might be useful:
class BasicUser(models.Model):
date_joined = models.DateTimeField(default=datetime.now)
but last-login might be better coupled with which
auth-backend/username was used, as a many2many relation:
class BasicUser(models.Model):
display_name = models.CharField(max_length=32)
date_joined = models.DateTimeField(default=datetime.now)
sightings = models.ManyToManyField(Sightings, ...)
@property
def last_seen(self):
# fetch last username/backend-combo from Sightings here
@property
def most_recent_username(self):
# fetch last username/backend-combo from Sightings here
This all assumes that there is more than one way to log in. But guess
what, that's what I'm increasingly seeing: log in with
yahoo/openid/facebook/whatever. Monoliths like django-socialauth is
not the solution (how do you add yet another login-method?) but it
certainly underlines the problem.
Let a thousand flowers bloom. Think. What do we really want. What do
we really need?
HM
I completely agree that we need to do something about #3011. If you
look at the voting, I'm +1 in favour - with the caveat that the most
recent patch on #3011 is *completely* the wrong approach.
However, the time has really past for big ticket discussions for v1.2,
and it certainly isn't the time to talk about ponies for v2.0. We've
just been through a 3 month process of discussing features, and this
discussion process consumes a lot of time. At some point, we (the
community) need to stop talking about features and start implementing
them, and we (the core team) needs to start integrating the work that
the community develops. That point is essentially now.
I don't want to dampen your enthusiasm here - I think this is a _very_
important problem, and your analysis covers many of the reasons why I
think this ticket is important, and the use cases that we need to
capture with any potential replacement. I just want to point out that
now isn't the best time to start an abstract discussion about big
changes.
Personally, I think you're on the right path - I think auth.User needs
to become a barebones model that is essentially just a primary key,
some datestamps for last login and last modified, and m2m relations
with permissions. Authentication should then be against a
profile-style model; calls like user.get_full_name should be deferred
to the information provided by the auth profile.
One of the big problems that needs to be solved that you haven't
addressed is the migration path. Obviously, we can't just replace the
current auth.User model - we need to have a migration plan for all
existing users of contrib.auth. I have some ideas on how this could be
done, but I'd be interested in hearing what others come up with. There
are also complications with integrating with admin that need to be
worked through.
So, if you want to play around with ideas in this space, I encourage
you to do so. Having a working implementation of an alternative auth
module would be a good starting point for discussions when we make the
call for proposals for v1.3.
If you need feedback on a design issue you confront, django-developers
is still the right place to ask. However, I want to moderate your
expectations regarding the level of intense design discussion that the
core will be able to engage in while simultaneously working on v1.2.
Yours,
Russ Magee %-)
Saying it's for 2.0 makes it possible to ignore backwards compatibility...
> I don't want to dampen your enthusiasm here /../ I just want to point out that
> now isn't the best time to start an abstract discussion about big
> changes.
I had to post the idea now in order to not forget it, though. It's
been simmering for months. This way it's just a google-search away.
> One of the big problems that needs to be solved that you haven't
> addressed is the migration path. Obviously, we can't just replace the
> current auth.User model - we need to have a migration plan for all
> existing users of contrib.auth.
auth.User as an "auth-profile" on the MinimalUser, then it could start
out looking exactly as today except having its primary key be a
foreign key. Then we could make some of the other fields on auth.User
fetch its data from minimalUser.
The tricky part IMO is getting 3rd parties to use the MinimalUser so I
foresee the big job as to rewrite tons of examples, tutorials, howtos.
Pushing it, basically. Oh and there should be screencasts, I love
those.
> I have some ideas on how this could be done, but I'd be interested
> in hearing what others come up with. There are also complications
> with integrating with admin that need to be worked through.
Sometimes it seems babying the admin is keeping us from doing a lot of
cool stuff. I couldn't use the admin at all in my very first django
project (legacy database + cranky DBA), so I guess I never grew used
to having it available.
> So, if you want to play around with ideas in this space, I encourage
> you to do so. Having a working implementation of an alternative auth
> module would be a good starting point for discussions when we make the
> call for proposals for v1.3.
NP, I'll make a branch to play with, have been looking for a good
excuse to learn git or mercurial better anyway :)
> If you need feedback on a design issue you confront, django-developers
> is still the right place to ask. However, I want to moderate your
> expectations regarding the level of intense design discussion that the
> core will be able to engage in while simultaneously working on v1.2.
What, you mean "no feedback whatsoever" is *not* the normal state of
affairs in all things in life? =)
HM
Possible doesn't necessarily mean encouraged, and there still needs to
be a clear migration path.
On top of that, 2.0 isn't "just around the corner" - its several years
away from even being a likely topic for discussion.
Lastly, if we can find a deprecation path rather than a backwards
incompatibility, we don't have to wait until 2.0 - we can do it in a
series of v1.X releases.
>> One of the big problems that needs to be solved that you haven't
>> addressed is the migration path. Obviously, we can't just replace the
>> current auth.User model - we need to have a migration plan for all
>> existing users of contrib.auth.
>
> auth.User as an "auth-profile" on the MinimalUser, then it could start
> out looking exactly as today except having its primary key be a
> foreign key. Then we could make some of the other fields on auth.User
> fetch its data from minimalUser.
That is an interesting approach - I hadn't considered that. There
might be some complications around models that have existing foreign
keys on User - obviously, they will continue to work, but if a foreign
key on MinimalUser is more appropriate, there is a different migration
issue.
> The tricky part IMO is getting 3rd parties to use the MinimalUser so I
> foresee the big job as to rewrite tons of examples, tutorials, howtos.
> Pushing it, basically. Oh and there should be screencasts, I love
> those.
... And I want a pony :-)
>> I have some ideas on how this could be done, but I'd be interested
>> in hearing what others come up with. There are also complications
>> with integrating with admin that need to be worked through.
>
> Sometimes it seems babying the admin is keeping us from doing a lot of
> cool stuff. I couldn't use the admin at all in my very first django
> project (legacy database + cranky DBA), so I guess I never grew used
> to having it available.
Like it or not, the admin has always been a big draw card feature of
Django. I know that the admin isn't perfect for every situation, but
I've also lot track of the amount of time it has saved me over the
years. I can guarantee you that any proposal that starts with "lets
ignore the admin" isn't going to get much traction with the core team.
Yours,
Russ Magee %-)