0
votes

I am attempting to use a backend authentication addition to have users authenticate by email, the user fails to authenticate by email and returns 'none'

backends.py

from django.contrib.auth.models import User


class EmailAuth():
    """Authenticate a user by an exact match on the email and password"""

    def authenticate(self, username=None, password=None):
        """
        Get an instance of `User` based off the email and verify the
        password
        """

        try:
            user = User.objects.get(email=username)

            if user.check_password(password):
                return user
            return None
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        """
        Used by the Django authentiation system to retrieve a user instance
        """

        try:
            user = User.objects.get(pk=user_id)
            if user.is_valid():
                return user
            return None
        except User.DoesNotExist:
            return None

accounts/settings.py

AUTHENTICATION_BACKENDS = [
'accounts.backends.EmailAuth',
'django.contrib.auth.backends.ModelBackend'
]

accounts/views.py excerpt, the user is 'None' but the username and password are passed to the authentication function

def login_by_email(request):
    """Return a login page"""
    if request.user.is_authenticated:
        return redirect(reverse('index'))
    if request.method == "POST":
        login_form = UserLoginForm(request.POST)

        if login_form.is_valid():
            user = auth.authenticate(username=request.POST['username'],
                                    password=request.POST['password'])

            # import pdb; pdb.set_trace()

            if user:
                login(user=user, request=request)
                # login(request, form.get_user())
                messages.success(request, "You have successfully logged in!")
                return redirect(reverse('index'))
            else:
                login_form.add_error(None, "Your username or password is incorrect")
    else:
        login_form = UserLoginForm()
    return render(request, 'login.html', {'login_form': login_form})

account/urls.py

from django.conf.urls import url, include
from accounts.views import logout, login_by_email, registration, user_profile
from accounts import urls_reset

urlpatterns = [
    url(r'^logout/', logout, name="logout"),
    url(r'^login/', login_by_email, name="login"),
    url(r'^register/', registration, name="registration"),
    url(r'^profile/', user_profile, name="profile"),
    url(r'', include(urls_reset))
]

root project urls.py

from django.conf.urls import url, include
from django.contrib import admin
from django.urls import path
from accounts.views import index
from accounts import urls as accounts_urls

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', index, name="index"),
    url(r'^accounts/', include(accounts_urls))
]

Working Solution with help from Ciaran Kehoe

backends.py

from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User

class EmailAuth():
    """
    Authenticate a user by an exact match on the email and password
    """

    def authenticate(self, request, username=None, password=None):

        try:
            user = User.objects.get(email=username)

            if user.check_password(password):
                return user
            return None
        except User.DoesNotExist:
            return None


    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

accounts/views.py

def login_by_email(request):
    """Return a login page"""
    if request.user.is_authenticated:
        return redirect(reverse('index'))
    if request.method == "POST":
        login_form = UserLoginForm(request.POST)
    if login_form.is_valid():
        user = auth.authenticate(request, username=request.POST['username'],
                                password=request.POST['password'])

        if user:
            login(request, user, backend='accounts.backends.EmailAuth')
            messages.success(request, "You have successfully logged in!")
            return redirect(reverse('index'))
        else:
            login_form.add_error(None, "Your username or password is incorrect")
else:
    login_form = UserLoginForm()
return render(request, 'login.html', {'login_form': login_form})
1
You have a typo here: user = User.onjects.get(pk=user_id) and you should rename login() view, because you're having a conflict here: login(user=user, request=request). - Borut
I have corrected the typo and rename the view but the user returned by the backends.EmailAuth.authenticate method is still none - Conor
Yeah, I saw later "working solution" that mentioned down in the question. It is known issue for those who is creating custom backend in django 2.1. Below i answered please mark as solved, It will instant help someone someday. Thanks. - Akhilendra

1 Answers

2
votes

You just need pass the request with your authenticate.

def authenticate(self, request, username=None, password=None):

    try:
        user = User.objects.get(email=username)

        if user.check_password(password):
            return user
        return None
    except User.DoesNotExist:
        return None