mirror of https://github.com/jumpserver/jumpserver
parent
c4eacbabc6
commit
81170b4b7b
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--/*@thymesVar id="LoginConstants" type="com.fit2cloud.support.common.constants.LoginConstants"*/-->
|
||||
<!--/*@thymesVar id="message" type="java.lang.String"*/-->
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<link rel="shortcut icon" href="{{ FAVICON_URL }}" type="image/x-icon">
|
||||
<link rel="shortcut icon" href="{{ FAVICON_URL }}" type="image/x-icon">
|
||||
<title>
|
||||
{{ JMS_TITLE }}
|
||||
</title>
|
||||
|
@ -16,6 +15,8 @@
|
|||
<link href="{% static 'css/font-awesome.min.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/bootstrap-style.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/login-style.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/style.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/jumpserver.css' %}" rel="stylesheet">
|
||||
|
||||
<!-- scripts -->
|
||||
<script src="{% static 'js/jquery-3.1.1.min.js' %}"></script>
|
||||
|
@ -24,26 +25,54 @@
|
|||
<script src="{% static 'js/plugins/datatables/datatables.min.js' %}"></script>
|
||||
|
||||
<style>
|
||||
.login-content {
|
||||
box-shadow: 0 5px 5px -3px rgb(0 0 0 / 20%), 0 8px 10px 1px rgb(0 0 0 / 14%), 0 3px 14px 2px rgb(0 0 0 / 12%);
|
||||
}
|
||||
|
||||
.box-1{
|
||||
.help-block {
|
||||
margin: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
form label {
|
||||
color: #737373;
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hr-line-dashed {
|
||||
border-top: 1px dashed #e7eaec;
|
||||
color: #ffffff;
|
||||
background-color: #ffffff;
|
||||
height: 1px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.login-content {
|
||||
height: 472px;
|
||||
width: 984px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
margin-top: calc((100vh - 470px)/2);
|
||||
|
||||
margin-top: calc((100vh - 470px) / 3);
|
||||
}
|
||||
.box-2{
|
||||
body {
|
||||
background-color: #f2f2f2;
|
||||
height: calc(100vh - (100vh - 470px) / 3);
|
||||
}
|
||||
|
||||
.right-image-box {
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
float: right;
|
||||
}
|
||||
.box-3{
|
||||
|
||||
.left-form-box {
|
||||
text-align: center;
|
||||
background-color: white;
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.captcha {
|
||||
float: right;
|
||||
}
|
||||
|
@ -56,136 +85,137 @@
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
.form-group.has-error {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.captch-field .has-error .help-block {
|
||||
margin-top: -8px !important;
|
||||
}
|
||||
|
||||
.no-captcha-challenge .form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.jms-title {
|
||||
padding: 40px 10px 10px;
|
||||
}
|
||||
|
||||
.no-captcha-challenge .jms-title {
|
||||
padding: 60px 10px 10px;
|
||||
}
|
||||
|
||||
.no-captcha-challenge .welcome-message {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.radio, .checkbox {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="height: 100%;font-size: 13px">
|
||||
<div>
|
||||
<div class="box-1">
|
||||
<div class="box-2">
|
||||
<img src="{{ LOGIN_IMAGE_URL }}" style="height: 100%; width: 100%"/>
|
||||
<body>
|
||||
<div class="login-content ">
|
||||
<div class="right-image-box">
|
||||
<img src="{{ LOGIN_IMAGE_URL }}" style="height: 100%; width: 100%"/>
|
||||
</div>
|
||||
<div class="left-form-box {% if not form.challenge and not form.captcha %} no-captcha-challenge {% endif %}">
|
||||
<div style="background-color: white">
|
||||
<div class="jms-title">
|
||||
<span style="font-size: 21px;font-weight:400;color: #151515;letter-spacing: 0;">{{ JMS_TITLE }}</span>
|
||||
</div>
|
||||
<div class="box-3">
|
||||
<div style="background-color: white">
|
||||
{% if form.challenge %}
|
||||
<div style="margin-top: 20px;padding-top: 30px;padding-left: 20px;padding-right: 20px;height: 60px">
|
||||
<div class="contact-form col-md-10 col-md-offset-1">
|
||||
<form id="login-form" action="" method="post" role="form" novalidate="novalidate">
|
||||
{% csrf_token %}
|
||||
<div style="line-height: 17px;margin-bottom: 20px;color: #999999;">
|
||||
{% if form.errors %}
|
||||
<p class="red-fonts" style="color: red">
|
||||
{% if form.non_field_errors %}
|
||||
{{ form.non_field_errors.as_text }}
|
||||
{% endif %}
|
||||
</p>
|
||||
{% else %}
|
||||
<div style="margin-top: 20px;padding-top: 40px;padding-left: 20px;padding-right: 20px;height: 80px">
|
||||
<p class="welcome-message">
|
||||
{% trans 'Welcome back, please enter username and password to login' %}
|
||||
</p>
|
||||
{% endif %}
|
||||
<span style="font-size: 21px;font-weight:400;color: #151515;letter-spacing: 0;">{{ JMS_TITLE }}</span>
|
||||
</div>
|
||||
<div style="font-size: 12px;color: #999999;letter-spacing: 0;line-height: 18px;margin-top: 18px">
|
||||
{% trans 'Welcome back, please enter username and password to login' %}
|
||||
</div>
|
||||
<div style="margin-bottom: 0px">
|
||||
<div>
|
||||
<div class="col-md-1"></div>
|
||||
<div class="contact-form col-md-10" style="margin-top: 0px;height: 35px">
|
||||
<form id="contact-form" action="" method="post" role="form" novalidate="novalidate">
|
||||
{% csrf_token %}
|
||||
{% if form.non_field_errors %}
|
||||
{% if form.challenge %}
|
||||
<div style="height: 50px;color: red;line-height: 17px;">
|
||||
{% else %}
|
||||
<div style="height: 70px;color: red;line-height: 17px;">
|
||||
{% endif %}
|
||||
<p class="red-fonts">{{ form.non_field_errors.as_text }}</p>
|
||||
</div>
|
||||
{% elif form.errors.captcha %}
|
||||
<p class="red-fonts">{% trans 'Captcha invalid' %}</p>
|
||||
{% else %}
|
||||
<div style="height: 50px"></div>
|
||||
{% endif %}
|
||||
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" name="{{ form.username.html_name }}" placeholder="{% trans 'Username' %}" required="" value="{% if form.username.value %}{{ form.username.value }}{% endif %}" style="height: 35px">
|
||||
{% if form.errors.username %}
|
||||
<div class="help-block field-error">
|
||||
<p class="red-fonts">{{ form.errors.username.as_text }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control" id="password" placeholder="{% trans 'Password' %}" required="">
|
||||
<input id="password-hidden" type="text" style="display:none" name="{{ form.password.html_name }}">
|
||||
{% if form.errors.password %}
|
||||
<div class="help-block field-error">
|
||||
<p class="red-fonts">{{ form.errors.password.as_text }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if form.challenge %}
|
||||
<div class="form-group">
|
||||
<input type="challenge" class="form-control" id="challenge" name="{{ form.challenge.html_name }}" placeholder="{% trans 'MFA code' %}" >
|
||||
{% if form.errors.challenge %}
|
||||
<div class="help-block field-error">
|
||||
<p class="red-fonts">{{ form.errors.challenge.as_text }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if form.captcha %}
|
||||
<div class="form-group" style="height: 50px;margin-bottom: 0;font-size: 13px">
|
||||
{{ form.captcha }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="form-group" style="height: 25px;margin-bottom: 0;font-size: 13px"></div>
|
||||
{% endif %}
|
||||
<div class="form-group" style="margin-top: 10px">
|
||||
<button type="submit" class="btn btn-transparent" onclick="doLogin();return false;">{% trans 'Login' %}</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{% if AUTH_OPENID or AUTH_CAS %}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div style="display: inline-block; float: left">
|
||||
<b class="text-muted text-left" style="margin-right: 10px">{% trans "More login options" %}</b>
|
||||
{% if AUTH_OPENID %}
|
||||
<a href="{% url 'authentication:openid:login' %}">
|
||||
<i class="fa fa-openid"></i> {% trans 'OpenID' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if AUTH_CAS %}
|
||||
<a href="{% url 'authentication:cas:cas-login' %}">
|
||||
<i class="fa"><img src="{{ LOGIN_CAS_LOGO_URL }}" height="13" width="13"></i> {% trans 'CAS' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="text-center" style="display: inline-block; float: right">
|
||||
{% else %}
|
||||
<div class="text-center" style="display: inline-block;">
|
||||
{% endif %}
|
||||
<a id="forgot_password" href="{% url 'authentication:forgot-password' %}">
|
||||
<small>{% trans 'Forgot password' %}?</small>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% bootstrap_field form.username show_label=False %}
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control" id="password" placeholder="{% trans 'Password' %}" required="">
|
||||
<input id="password-hidden" type="text" style="display:none" name="{{ form.password.html_name }}">
|
||||
</div>
|
||||
{% if form.challenge %}
|
||||
{% bootstrap_field form.challenge show_label=False %}
|
||||
{% elif form.captcha %}
|
||||
<div class="captch-field">
|
||||
{% bootstrap_field form.captcha show_label=False %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="form-group" style="padding-top: 5px; margin-bottom: 10px">
|
||||
<div class="row">
|
||||
<div class="col-md-6" style="text-align: left">
|
||||
{% if form.auto_login %}
|
||||
{% bootstrap_field form.auto_login form_group_class='' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<a id="forgot_password" href="{% url 'authentication:forgot-password' %}" style="float: right">
|
||||
<small>{% trans 'Forgot password' %}?</small>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="">
|
||||
<button type="submit" class="btn btn-transparent" onclick="doLogin();return false;">{% trans 'Login' %}</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{% if AUTH_OPENID or AUTH_CAS %}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div style="display: inline-block; float: left">
|
||||
<b class="text-muted text-left" style="margin-right: 10px">{% trans "More login options" %}</b>
|
||||
{% if AUTH_OPENID %}
|
||||
<a href="{% url 'authentication:openid:login' %}" class="more-login-item">
|
||||
<i class="fa fa-openid"></i> {% trans 'OpenID' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if AUTH_CAS %}
|
||||
<a href="{% url 'authentication:cas:cas-login' %}" class="more-login-item">
|
||||
<i class="fa"><img src="{{ LOGIN_CAS_LOGO_URL }}" height="13" width="13"></i> {% trans 'CAS' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center" style="display: inline-block;">
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="/static/js/plugins/jsencrypt/jsencrypt.min.js"></script>
|
||||
<script>
|
||||
function encryptLoginPassword(password, rsaPublicKey){
|
||||
function encryptLoginPassword(password, rsaPublicKey) {
|
||||
var jsencrypt = new JSEncrypt(); //加密对象
|
||||
jsencrypt.setPublicKey(rsaPublicKey); // 设置密钥
|
||||
return jsencrypt.encrypt(password); //加密
|
||||
}
|
||||
|
||||
function doLogin() {
|
||||
//公钥加密
|
||||
var rsaPublicKey = "{{ rsa_public_key }}"
|
||||
var password =$('#password').val(); //明文密码
|
||||
var password = $('#password').val(); //明文密码
|
||||
var passwordEncrypted = encryptLoginPassword(password, rsaPublicKey)
|
||||
$('#password-hidden').val(passwordEncrypted); //返回给密码输入input
|
||||
$('#contact-form').submit();//post提交
|
||||
$('#login-form').submit();//post提交
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
|
|
|
@ -122,6 +122,13 @@ class UserLoginGuardView(mixins.AuthMixin, RedirectView):
|
|||
url = "%s?%s" % (url, args)
|
||||
return url
|
||||
|
||||
def login_it(self, user):
|
||||
auth_login(self.request, user)
|
||||
# 如果设置了自动登录,那需要设置 session_id cookie 的有效期
|
||||
if self.request.session.get('auto_login'):
|
||||
age = self.request.session.get_expiry_age()
|
||||
self.request.session.set_expiry(age)
|
||||
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
try:
|
||||
user = self.check_user_auth_if_need()
|
||||
|
@ -138,7 +145,7 @@ class UserLoginGuardView(mixins.AuthMixin, RedirectView):
|
|||
except errors.PasswdTooSimple as e:
|
||||
return e.url
|
||||
else:
|
||||
auth_login(self.request, user)
|
||||
self.login_it(user)
|
||||
self.send_auth_signal(success=True, user=user)
|
||||
self.clear_auth_mark()
|
||||
url = redirect_user_first_login_or_index(
|
||||
|
|
|
@ -285,6 +285,8 @@ class Config(dict):
|
|||
'ONLY_ALLOW_EXIST_USER_AUTH': False,
|
||||
'ONLY_ALLOW_AUTH_FROM_SOURCE': True,
|
||||
'DISK_CHECK_ENABLED': True,
|
||||
'SESSION_SAVE_EVERY_REQUEST': True,
|
||||
'SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE': False,
|
||||
}
|
||||
|
||||
def compatible_auth_openid_of_key(self):
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
from django.templatetags.static import static
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
|
||||
def jumpserver_processor(request):
|
||||
|
@ -14,7 +14,7 @@ def jumpserver_processor(request):
|
|||
'LOGIN_IMAGE_URL': static('img/login_image.png'),
|
||||
'FAVICON_URL': static('img/facio.ico'),
|
||||
'LOGIN_CAS_LOGO_URL': static('img/login_cas_logo.png'),
|
||||
'JMS_TITLE': 'JumpServer',
|
||||
'JMS_TITLE': _('JumpServer Open Source PAM'),
|
||||
'VERSION': settings.VERSION,
|
||||
'COPYRIGHT': 'FIT2CLOUD 飞致云' + ' © 2014-2021',
|
||||
'SECURITY_COMMAND_EXECUTION': settings.SECURITY_COMMAND_EXECUTION,
|
||||
|
|
|
@ -120,7 +120,10 @@ LOGIN_URL = reverse_lazy('authentication:login')
|
|||
SESSION_COOKIE_DOMAIN = CONFIG.SESSION_COOKIE_DOMAIN
|
||||
CSRF_COOKIE_DOMAIN = CONFIG.CSRF_COOKIE_DOMAIN
|
||||
SESSION_COOKIE_AGE = CONFIG.SESSION_COOKIE_AGE
|
||||
SESSION_EXPIRE_AT_BROWSER_CLOSE = CONFIG.SESSION_EXPIRE_AT_BROWSER_CLOSE
|
||||
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
|
||||
# 自定义的配置,SESSION_EXPIRE_AT_BROWSER_CLOSE 始终为 True, 下面这个来控制是否强制关闭后过期 cookie
|
||||
SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE = CONFIG.SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE
|
||||
SESSION_SAVE_EVERY_REQUEST = CONFIG.SESSION_SAVE_EVERY_REQUEST
|
||||
SESSION_ENGINE = 'redis_sessions.session'
|
||||
SESSION_REDIS = {
|
||||
'host': CONFIG.REDIS_HOST,
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -31,7 +31,6 @@
|
|||
background-color: transparent;
|
||||
border: 1px solid #dedede;
|
||||
box-shadow: none;
|
||||
height: 45px !important;
|
||||
color: #0c0c0c;
|
||||
height: 30px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Neue Haas Grotesk Text Pro", "Arial Nova", "Segoe UI", "Helvetica Neue", ".PingFang SC", "PingFang SC", "Microsoft YaHei", "Microsoft JhengHei", "Source Han Sans SC", "Noto Sans CJK SC", "Source Han Sans CN", "Noto Sans SC", "Source Han Sans TC", "Noto Sans CJK TC", "Hiragino Sans GB", sans-serif;
|
||||
|
@ -242,7 +241,6 @@ fieldset[disabled] .btn-login.active {
|
|||
background-color: transparent;
|
||||
border: 1px solid #dedede;
|
||||
box-shadow: none;
|
||||
height: 45px !important;
|
||||
color: #0c0c0c;
|
||||
height: 38px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Neue Haas Grotesk Text Pro", "Arial Nova", "Segoe UI", "Helvetica Neue", ".PingFang SC", "PingFang SC", "Microsoft YaHei", "Microsoft JhengHei", "Source Han Sans SC", "Noto Sans CJK SC", "Source Han Sans CN", "Noto Sans SC", "Source Han Sans TC", "Noto Sans CJK TC", "Hiragino Sans GB", sans-serif;
|
||||
|
@ -274,13 +272,13 @@ fieldset[disabled] .btn-login.active {
|
|||
|
||||
.btn-transparent {
|
||||
color: #fff;
|
||||
border: 1px solid #fff;
|
||||
border: 1px solid #1ab394;
|
||||
display: inline-block;
|
||||
font-size: 13px;
|
||||
letter-spacing: 1px;
|
||||
padding: 14px 35px;
|
||||
padding: 10px 30px;
|
||||
text-transform: uppercase;
|
||||
border-radius: 40px;
|
||||
border-radius: 5px;
|
||||
background: #259980;
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -66,12 +66,6 @@ class UserProfileApi(generics.RetrieveUpdateAPIView):
|
|||
def get_object(self):
|
||||
return self.request.user
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
if not settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
|
||||
age = request.session.get_expiry_age()
|
||||
request.session.set_expiry(age)
|
||||
return super().retrieve(request, *args, **kwargs)
|
||||
|
||||
|
||||
class UserPasswordApi(generics.RetrieveUpdateAPIView):
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
|
|
@ -3,6 +3,14 @@
|
|||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% block custom_head_css_js %}
|
||||
<style>
|
||||
.captcha {
|
||||
float: right;
|
||||
}
|
||||
#id_captcha_1 {
|
||||
width: 50%;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block html_title %}{% trans 'Forgot password' %}{% endblock %}
|
||||
{% block title %} {% trans 'Forgot password' %}?{% endblock %}
|
||||
|
|
Loading…
Reference in New Issue