簡體   English   中英

在Django身份驗證期間單獨驗證用戶名和密碼

[英]Separately validating username and password during Django authentication

在django中使用標准身份驗證模塊時,失敗的用戶身份驗證不明確。 也就是說,似乎無法區分以下兩種情況:

  • 用戶名有效,密碼無效
  • 用戶名無效

我想我想在這兩種情況下向用戶顯示相應的消息,而不是單個“用戶名或密碼無效......”。

任何人都有使用簡單方法的經驗。 問題的症結似乎是在最低級別 - 在django.contrib.auth.backends.ModelBackend類中。 此類的authenticate()方法(以用戶名和密碼作為參數)僅在身份驗證成功時返回User對象,如果身份驗證失敗則返回None。 鑒於此代碼處於最低級別(好,最低級別高於數據庫代碼),繞過它似乎很多代碼被拋棄了。

簡單地實現新的身份驗證后端並將其添加到AUTHENTICATION_BACKENDS設置是最好的方法嗎? 可以實現返回(User,Bool)元組的后端,其中如果用戶名不存在,則User對象僅為None,如果密碼正確,則Bool僅為True。 但是,這會破壞后端與django.contrib.auth.authenticate()方法的約定( 記錄為在成功驗證時返回User對象,否則為None)。

也許,這一切都是無所顧忌? 無論用戶名或密碼是否不正確,用戶可能無論如何都必須轉到“忘記密碼”頁面,所以這可能都是學術性的。 我只是忍不住感覺,不過......

編輯:

關於我選擇的答案的評論:我選擇的答案是實現此功能的方法。 下面還有另一個答案,討論了這樣做的潛在安全隱患,我也將其視為提名的答案。 但是,我提名的答案解釋了如何實現此功能。 基於安全性的答案討論了是否應該實現這個功能,這實際上是一個不同的問題。

你真的不想區分這兩種情況。 否則,您將為潛在的黑客提供關於用戶名是否有效的線索 - 這對獲取欺詐性登錄有重大幫助。

這不僅僅是后端的功能,只是身份驗證表單。 只需重寫表單即可顯示每個字段所需的錯誤。 編寫一個使用新表單的登錄視圖,並將其設置為默認登錄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

我們必須在使用外部會員訂閱服務的網站上處理此問題。 基本上你做

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

在我們的例子中,如果用戶名不存在,那么我們必須檢查由外部站點的Perl腳本更新的HTPASSWD文件。 如果文件中存在名稱,那么我們將創建用戶,設置密碼,然后執行身份驗證。

這個答案並不是Django特有的,但這是我用來完成這個的偽代碼:

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

//If true
    //successful login!

//If false
    //Query if user exists who's username=<username>
        //If true
            //This means the user typed in the wrong password
        //If false
            //This means the user typed in the wrong username
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.\
                """)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM