OpenEdx用户登录失败次数过多导致的账户锁定问题

       使用OpenEdx的过程中发现,当用户频繁登录失败会导致账号锁定。跟踪代码发现,相关的中文对应的英文如下:
This account has been temporarily locked due to excessive login failures
       根据英文提示,找到在dogwood中对应的代码位置如下(在新版本中已经不再这个文件了):

#common/djangoapps/student/views.py
...
@ensure_csrf_cookie
def login_user(request, error=""):  # pylint: disable=too-many-statements,unused-argument
    """AJAX request to log in the user."""
....
    # see if account has been locked out due to excessive login failures
    user_found_by_email_lookup = user
    if user_found_by_email_lookup and LoginFailures.is_feature_enabled():
        if LoginFailures.is_user_locked_out(user_found_by_email_lookup):
            return JsonResponse({
                "success": False,
                "value": _('This account has been temporarily locked due to excessive login failures. Try again later.'),
            })  # TODO: this should be status code 429  # pylint: disable=fixme
....
     其中关键的代码是”LoginFailures”这个类,定义如下。在settings已经有个参数控制超时时间:
#common/djangoapps/student/models.py
...
class LoginFailures(models.Model):
    """
    This model will keep track of failed login attempts
    """
    user = models.ForeignKey(User)
    failure_count = models.IntegerField(default=0)
    lockout_until = models.DateTimeField(null=True)
......
    @classmethod
    def is_user_locked_out(cls, user):
        """
        Static method to return in a given user has his/her account locked out
        """
        try:
            record = LoginFailures.objects.get(user=user)
            if not record.lockout_until:
                return False
            now = datetime.now(UTC)
            until = record.lockout_until
            is_locked_out = until and now < until
            return is_locked_out
        except ObjectDoesNotExist:
            return False

    @classmethod
    def increment_lockout_counter(cls, user):
        """
        Ticks the failed attempt counter
        """
        record, _ = LoginFailures.objects.get_or_create(user=user)
        record.failure_count = record.failure_count + 1
        max_failures_allowed = settings.MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED

        # did we go over the limit in attempts
        if record.failure_count >= max_failures_allowed:
            # yes, then store when this account is locked out until
            lockout_period_secs = settings.MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS
            record.lockout_until = datetime.now(UTC) + timedelta(seconds=lockout_period_secs)

 
        record.save()
     其中increment_lockout_count控制锁定账号,而settings.MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS控制了当账号被锁时,锁定多长时间。在配置文件部分可以找到相关设置:
#lms/envs/common.py
...
##### ACCOUNT LOCKOUT DEFAULT PARAMETERS #####
MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED = 5
MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS = 15 * 60
.....
    从参数可以看出,锁定账号默认时间时15分钟,错误次数时5次。

发表评论

电子邮件地址不会被公开。 必填项已用*标注