diff --git a/apps/authentication/forms.py b/apps/authentication/forms.py index fe28edb68..447d842bd 100644 --- a/apps/authentication/forms.py +++ b/apps/authentication/forms.py @@ -8,11 +8,26 @@ from captcha.fields import CaptchaField, CaptchaTextInput class UserLoginForm(forms.Form): - username = forms.CharField(label=_('Username'), max_length=100) + days_auto_login = int(settings.SESSION_COOKIE_AGE / 3600 / 24) + disable_days_auto_login = settings.SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE or days_auto_login < 1 + + username = forms.CharField( + label=_('Username'), max_length=100, + widget=forms.TextInput(attrs={ + 'placeholder': _("Username"), + 'autofocus': 'autofocus' + }) + ) password = forms.CharField( label=_('Password'), widget=forms.PasswordInput, max_length=1024, strip=False ) + auto_login = forms.BooleanField( + label=_("{} days auto login").format(days_auto_login or 1), + required=False, initial=False, widget=forms.CheckboxInput( + attrs={'disabled': disable_days_auto_login} + ) + ) def confirm_login_allowed(self, user): if not user.is_staff: @@ -35,8 +50,13 @@ class CaptchaMixin(forms.Form): class ChallengeMixin(forms.Form): - challenge = forms.CharField(label=_('MFA code'), max_length=6, - required=False) + challenge = forms.CharField( + label=_('MFA code'), max_length=6, required=False, + widget=forms.TextInput(attrs={ + 'placeholder': _("MFA code"), + 'style': 'width: 50%' + }) + ) def get_user_login_form_cls(*, captcha=False): diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py index e4813ef3f..9702e6046 100644 --- a/apps/authentication/mixins.py +++ b/apps/authentication/mixins.py @@ -82,7 +82,7 @@ class AuthMixin: return raw_passwd def raise_credential_error(self, error): - raise self.partial_credential_error(error=errors.reason_password_decrypt_failed) + raise self.partial_credential_error(error=error) def get_auth_data(self, decrypt_passwd=False): request = self.request @@ -91,8 +91,8 @@ class AuthMixin: else: data = request.POST - items = ['username', 'password', 'challenge', 'public_key'] - username, password, challenge, public_key = bulk_get(data, *items, default='') + items = ['username', 'password', 'challenge', 'public_key', 'auto_login'] + username, password, challenge, public_key, auto_login = bulk_get(data, *items, default='') password = password + challenge.strip() ip = self.get_request_ip() self.partial_credential_error = partial(errors.CredentialError, username=username, ip=ip, request=request) @@ -101,7 +101,7 @@ class AuthMixin: password = self.decrypt_passwd(password) if not password: self.raise_credential_error(errors.reason_password_decrypt_failed) - return username, password, public_key, ip + return username, password, public_key, ip, auto_login def _check_only_allow_exists_user_auth(self, username): # 仅允许预先存在的用户认证 @@ -131,7 +131,7 @@ class AuthMixin: def check_user_auth(self, decrypt_passwd=False): self.check_is_block() request = self.request - username, password, public_key, ip = self.get_auth_data(decrypt_passwd=decrypt_passwd) + username, password, public_key, ip, auto_login = self.get_auth_data(decrypt_passwd=decrypt_passwd) self._check_only_allow_exists_user_auth(username) user = self._check_auth_user_is_valid(username, password, public_key) @@ -145,6 +145,7 @@ class AuthMixin: clean_failed_count(username, ip) request.session['auth_password'] = 1 request.session['user_id'] = str(user.id) + request.session['auto_login'] = auto_login request.session['auth_backend'] = auth_backend return user diff --git a/apps/authentication/templates/authentication/login.html b/apps/authentication/templates/authentication/login.html index e06567aa4..9866537ba 100644 --- a/apps/authentication/templates/authentication/login.html +++ b/apps/authentication/templates/authentication/login.html @@ -1,12 +1,11 @@ -{% load static %} {% load i18n %} +{% load bootstrap3 %} +{% load static %} - - - + {{ JMS_TITLE }} @@ -16,6 +15,8 @@ + + @@ -24,26 +25,54 @@ - -
-
-
- + +