Separately checking username and password during Django authentication

When using the standard authentication module in django, failed user authentication is ambiguous. Namely, there seems to be no way to distinguish between the following two scenarios:

  • Username was valid, password was invalid
  • Invalid username

I think that I would like to display the corresponding messages to the user in these two cases, and not one "username or password was invalid ...".

Anyone has experience with simple ways to do this. The bottom line seems to go right to the lowest level - in the django.contrib.auth.backends.ModelBackend class. The authenticate () method of this class, which takes a username and password as arguments, simply returns a User object if authentication succeeded, or None if authentication failed. Given that this code is at the lowest level (well, the lowest level that is higher than the database code), bypassing it it seems that a lot of code is being thrown.

Is it best to just implement a new authentication server and add it to the AUTHENTICATION_BACKENDS setting? A backend can be implemented that returns a tuple (User, Bool), where the User object is only None if the username does not exist, and Bool is only True if the password was right. This, however, will violate a contract that has a backend with the django.contrib.auth.authenticate () method (which is documented to return a User object on successful authentication and None otherwise).

Maybe it's all worry about nothing? Regardless of whether the username or password was incorrect, the user will probably have to go to the Forgot Password page all the time, so maybe this is all academic. I just can't help but feel ...

EDIT:

, : , , - . , , . , , , . , , , , , , .

+5
5

, . , , . , , URL- . (, Django, , ). 5 . , , django.contrib.auth.

:

class AuthenticationForm(forms.Form):
    """
    Base class for authenticating users. Extend this to get a form that accepts
    username/password logins.
    """
    username = forms.CharField(label=_("Username"), max_length=30)
    password = forms.CharField(label=_("Password"), widget=forms.PasswordInput)

    def __init__(self, request=None, *args, **kwargs):
        """
        If request is passed in, the form will validate that cookies are
        enabled. Note that the request (a HttpRequest object) must have set a
        cookie with the key TEST_COOKIE_NAME and value TEST_COOKIE_VALUE before
        running this validation.
        """
        self.request = request
        self.user_cache = None
        super(AuthenticationForm, self).__init__(*args, **kwargs)

    def clean(self):
        username = self.cleaned_data.get('username')
        password = self.cleaned_data.get('password')

        if username and password:
            self.user_cache = authenticate(username=username, password=password)
            if self.user_cache is None:
                raise forms.ValidationError(_("Please enter a correct username and password. Note that both fields are case-sensitive."))
            elif not self.user_cache.is_active:
                raise forms.ValidationError(_("This account is inactive."))

        # TODO: determine whether this should move to its own method.
        if self.request:
            if not self.request.session.test_cookie_worked():
                raise forms.ValidationError(_("Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in."))

        return self.cleaned_data

    def get_user_id(self):
        if self.user_cache:
            return self.user_cache.id
        return None

    def get_user(self):
        return self.user_cache

def clean_username(self):
    username = self.cleaned_data['username']
    try:
        User.objects.get(username=username)
    except User.DoesNotExist:
        raise forms.ValidationError("The username you have entered does not exist.")
    return username
+2

. , - .

+19

, .

from django.contrib.auth.models import User

try:
    user = User.objects.get(username=whatever)
    # if you get here the username exists and you can do a normal authentication
except:
    pass # no such username

, , HTPASSWD, Perl script . , , , auth.

0

Django, , :

//Query if user exists who username=<username> and password=<password>

//If true
    //successful login!

//If false
    //Query if user exists who username=<username>
        //If true
            //This means the user typed in the wrong password
        //If false
            //This means the user typed in the wrong username
0
def clean_username(self):
    """
    Verifies that the username is available.
    """
    username = self.cleaned_data["username"]
    try:
        user = User.objects.get(username=username)
    except User.DoesNotExist:
        return username
    else:
        raise forms.ValidationError(u"""\
                This username is already registered, 
                please choose another one.\
                """)
0

All Articles