I guess I'm not clear on what you are trying to achieve. There are a couple
of scenarios to consider.

As it stands with the default contrib.auth authentication backend, sending
both the username and email address entered by the user will only work IF
the user registered/was created using their email address as their
username, meaning that user.username is either their username (a string
that isn't their email), or an email address, regardless of what user.email
returns. The default contrib.auth authentication backend only looks at
user.username.

What I suspect you want is to be able to use either user.username OR
user.email as the identifying tokens for the user in order to authenticate
them. For that, you'll need to roll at least a partial custom
authentication backend, in addition to the changes for the forms, etc. that
you've already laid out.

From
https://docs.djangoproject.com/en/1.7/topics/auth/customizing/#writing-an-authentication-backend
:

"If you wish to provide custom behavior for only part of the backend API,
you can take advantage of Python inheritance and subclass *ModelBackend*
instead of implementing the complete API in a custom backend."

Specifically, you'll need to override the authenticate() method of the
authentication backend.

I've done this, it's actually pretty easy. See:

https://github.com/django/django/blob/master/django/contrib/auth/backends.py#L11

In this case, you should also roll a custom user model as well to ensure
that both user.username and user.email are unique columns. If you use the
email address as an identifying token, it will need to be unique among all
users, which is not true/enforced for the built-in contrib.auth User model.
You will also need to override the custom User manager for your new
CustomUser, probably with and override for get_by_natural_key(token) so
that the user can be retrieved in the backend authenticate() method. The
key change in get_by_natural_key() being the filter for the user object
being changed to something like User.objects.get(Q(username=token) |
Q(email=token)).

(If you haven't seen the Q() notation, check
https://docs.djangoproject.com/en/1.7/ref/models/queries/#q-objects)

The custom user you probably want is somewhat similar to the example given
in the docs:

https://docs.djangoproject.com/en/1.7/topics/auth/customizing/#a-full-example

You'll need to add a 'username' field back in (remember to make it unique)
along with several other tweaks to be able to use either a username or
email field. An alternative would be a custom user class inheriting from
AbstractBaseUser and copying in the goodies you need from AbstractUser
(which is probably everything except the username and email fields, which
you'll be defining as unique). Be sure to include the Permission mixins
that AbstractUser has if you intend to use the built-in permission system
with your CustomUser.

Sorry about the lengthy message, there are a bunch of ways to tackle this,
but ultimately I think you'll be rolling your own user and at least part of
the authentication system, not to mention having to customize the user
forms. The user will be slightly tricky, as there is no clear inheritance
path that will make it easy AFAICT, but the auth backend should be just a
class with a single authenticate() function if you inherit from
ModelBackend. Be sure to either include your custom backend in
AUTHENTICATION_BACKENDS, or possibly even replacing it if you go with the
Q() query I specified earlier (since an auth request using an email would
generate two authentication queries if both backends are used, and the
username field is checked twice).

TL;DR; Overriding the user forms is probably not enough, you'll need a
custom user and custom authentication backend.

Not sure if I made the situation better or worse, but HTH...

Obviously, YMMV, I haven't tried this myself, but I have done a fair bit of
overriding for a custom object-based permission system, which touches many
of the same structures above.

-James






On Mon, Jan 19, 2015 at 1:26 AM, Abraham Varricatt <
abraham.varric...@googlemail.com> wrote:

> Ignoring the malformed code, will the call to authenticate() even work
> without username? According to the docs,
>
> https://docs.djangoproject.com/en/1.7/topics/auth/default/#django.contrib.auth.authenticate
>
> It takes credentials in the form of keyword arguments, for the default
>> configuration this is username and password, and it returns a User
>> <https://docs.djangoproject.com/en/1.7/ref/contrib/auth/#django.contrib.auth.models.User>
>> object if the password is valid for the given username.
>>
>>
> If someone wanted to change the default behavior, I would expect them to
> at least override the function. OP doesn't seem to have done this, so it
> shouldn't even work. (Please correct me if I'm missing something)
>
> -Abraham V.
>
> On Friday, January 16, 2015 at 2:37:13 AM UTC+5:30, Matt Cooper wrote:
>>
>> Your if block in views.py is not well-formed. I haven't tested this but
>> I'd write it more like this:
>>
>>     # try username
>>     user = auth.authenticate(username=username, password=password)
>>     if user is not None:
>>         auth.login(request, user)
>>         return HttpResponseRedirect('/')
>>     # fall-through to email
>>     user = auth.authenticate(email=username, password=password)
>>     if user is not None:
>>         auth.login(request, user)
>>         return HttpResponseRedirect('/')
>>     # ok, neither one worked
>>     return HttpResponseRedirect('/accounts/invalid_login')
>>
>>
>> On Wednesday, January 14, 2015 at 10:07:29 PM UTC-8, Kakar Nyori wrote:
>>
>>> I have extendted the *UserCreationForm* with email and other fields, so
>>> that I could authenticate a user with both its username and email.
>>>
>>> forms.py:
>>>
>>>> class UserCreationForm(UserCreationForm):
>>>> class Meta:
>>>> model = User
>>>> fields = ('first_name', 'last_name', 'username', 'email',)
>>>
>>>
>>>
>>> views.py:
>>>
>>> def auth_view(request):
>>>>     username = request.POST.get('username','')
>>>>     password = request.POST.get('password','')
>>>>     user = auth.authenticate(username=username, password=password)
>>>>     if user is not None:
>>>>         auth.login(request, user)
>>>>         return HttpResponseRedirect('/')
>>>>     elif:
>>>>         user = auth.authenticate(email=username, password=password)
>>>>         if user is not None:
>>>>             auth.login(request, user)
>>>>             return HttpResponseRedirect('/')
>>>>     else:
>>>>         return HttpResponseRedirect('/accounts/invalid_login')
>>>
>>>
>>> html:
>>>
>>> <form action="/accounts/auth/" method="post">
>>>>     {%csrf_token%}
>>>>     <label for="name">Email or Username:</label>
>>>>     <input type="text" name="name" id="name" value="">
>>>>     <label for="password">Password:</label>
>>>>     <input type="password" name="password" id="password" value="">
>>>>     <input type="submit" value="LOGIN">
>>>> </form>
>>>
>>>
>>>
>>> In the views I tried giving both the *username* and *email *as input
>>> from the form as *name*, and check to see if username and password
>>> authenticate. If not then check whether email and password authenticate.
>>> But its not working. How do I solve this problem? Please kindly help me.
>>> Thank you.
>>>
>>  --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-users+unsubscr...@googlegroups.com.
> To post to this group, send email to django-users@googlegroups.com.
> Visit this group at http://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/c7e27779-311b-43f4-b66d-d3548becdc26%40googlegroups.com
> <https://groups.google.com/d/msgid/django-users/c7e27779-311b-43f4-b66d-d3548becdc26%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CA%2Be%2BciVB2vT24q%2BZ_sTqWe2pXfY-6rCpg4MLTavEtfjJcLTEEA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to