使用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次。