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):
|
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(
|
password = forms.CharField(
|
||||||
label=_('Password'), widget=forms.PasswordInput,
|
label=_('Password'), widget=forms.PasswordInput,
|
||||||
max_length=1024, strip=False
|
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):
|
def confirm_login_allowed(self, user):
|
||||||
if not user.is_staff:
|
if not user.is_staff:
|
||||||
|
@ -35,8 +50,13 @@ class CaptchaMixin(forms.Form):
|
||||||
|
|
||||||
|
|
||||||
class ChallengeMixin(forms.Form):
|
class ChallengeMixin(forms.Form):
|
||||||
challenge = forms.CharField(label=_('MFA code'), max_length=6,
|
challenge = forms.CharField(
|
||||||
required=False)
|
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):
|
def get_user_login_form_cls(*, captcha=False):
|
||||||
|
|
|
@ -82,7 +82,7 @@ class AuthMixin:
|
||||||
return raw_passwd
|
return raw_passwd
|
||||||
|
|
||||||
def raise_credential_error(self, error):
|
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):
|
def get_auth_data(self, decrypt_passwd=False):
|
||||||
request = self.request
|
request = self.request
|
||||||
|
@ -91,8 +91,8 @@ class AuthMixin:
|
||||||
else:
|
else:
|
||||||
data = request.POST
|
data = request.POST
|
||||||
|
|
||||||
items = ['username', 'password', 'challenge', 'public_key']
|
items = ['username', 'password', 'challenge', 'public_key', 'auto_login']
|
||||||
username, password, challenge, public_key = bulk_get(data, *items, default='')
|
username, password, challenge, public_key, auto_login = bulk_get(data, *items, default='')
|
||||||
password = password + challenge.strip()
|
password = password + challenge.strip()
|
||||||
ip = self.get_request_ip()
|
ip = self.get_request_ip()
|
||||||
self.partial_credential_error = partial(errors.CredentialError, username=username, ip=ip, request=request)
|
self.partial_credential_error = partial(errors.CredentialError, username=username, ip=ip, request=request)
|
||||||
|
@ -101,7 +101,7 @@ class AuthMixin:
|
||||||
password = self.decrypt_passwd(password)
|
password = self.decrypt_passwd(password)
|
||||||
if not password:
|
if not password:
|
||||||
self.raise_credential_error(errors.reason_password_decrypt_failed)
|
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):
|
def _check_only_allow_exists_user_auth(self, username):
|
||||||
# 仅允许预先存在的用户认证
|
# 仅允许预先存在的用户认证
|
||||||
|
@ -131,7 +131,7 @@ class AuthMixin:
|
||||||
def check_user_auth(self, decrypt_passwd=False):
|
def check_user_auth(self, decrypt_passwd=False):
|
||||||
self.check_is_block()
|
self.check_is_block()
|
||||||
request = self.request
|
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)
|
self._check_only_allow_exists_user_auth(username)
|
||||||
user = self._check_auth_user_is_valid(username, password, public_key)
|
user = self._check_auth_user_is_valid(username, password, public_key)
|
||||||
|
@ -145,6 +145,7 @@ class AuthMixin:
|
||||||
clean_failed_count(username, ip)
|
clean_failed_count(username, ip)
|
||||||
request.session['auth_password'] = 1
|
request.session['auth_password'] = 1
|
||||||
request.session['user_id'] = str(user.id)
|
request.session['user_id'] = str(user.id)
|
||||||
|
request.session['auto_login'] = auto_login
|
||||||
request.session['auth_backend'] = auth_backend
|
request.session['auth_backend'] = auth_backend
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
{% load static %}
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
{% load static %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<!--/*@thymesVar id="LoginConstants" type="com.fit2cloud.support.common.constants.LoginConstants"*/-->
|
|
||||||
<!--/*@thymesVar id="message" type="java.lang.String"*/-->
|
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
<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">
|
||||||
|
@ -16,6 +15,8 @@
|
||||||
<link href="{% static 'css/font-awesome.min.css' %}" rel="stylesheet">
|
<link href="{% static 'css/font-awesome.min.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'css/bootstrap-style.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/login-style.css' %}" rel="stylesheet">
|
||||||
|
<link href="{% static 'css/style.css' %}" rel="stylesheet">
|
||||||
|
<link href="{% static 'css/jumpserver.css' %}" rel="stylesheet">
|
||||||
|
|
||||||
<!-- scripts -->
|
<!-- scripts -->
|
||||||
<script src="{% static 'js/jquery-3.1.1.min.js' %}"></script>
|
<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>
|
<script src="{% static 'js/plugins/datatables/datatables.min.js' %}"></script>
|
||||||
|
|
||||||
<style>
|
<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;
|
height: 472px;
|
||||||
width: 984px;
|
width: 984px;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-left: 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%;
|
height: 100%;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
.box-3{
|
|
||||||
|
.left-form-box {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.captcha {
|
.captcha {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
@ -56,82 +85,92 @@
|
||||||
text-align: left;
|
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>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body style="height: 100%;font-size: 13px">
|
<body>
|
||||||
<div>
|
<div class="login-content ">
|
||||||
<div class="box-1">
|
<div class="right-image-box">
|
||||||
<div class="box-2">
|
|
||||||
<img src="{{ LOGIN_IMAGE_URL }}" style="height: 100%; width: 100%"/>
|
<img src="{{ LOGIN_IMAGE_URL }}" style="height: 100%; width: 100%"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-3">
|
<div class="left-form-box {% if not form.challenge and not form.captcha %} no-captcha-challenge {% endif %}">
|
||||||
<div style="background-color: white">
|
<div style="background-color: white">
|
||||||
{% if form.challenge %}
|
<div class="jms-title">
|
||||||
<div style="margin-top: 20px;padding-top: 30px;padding-left: 20px;padding-right: 20px;height: 60px">
|
|
||||||
{% else %}
|
|
||||||
<div style="margin-top: 20px;padding-top: 40px;padding-left: 20px;padding-right: 20px;height: 80px">
|
|
||||||
{% endif %}
|
|
||||||
<span style="font-size: 21px;font-weight:400;color: #151515;letter-spacing: 0;">{{ JMS_TITLE }}</span>
|
<span style="font-size: 21px;font-weight:400;color: #151515;letter-spacing: 0;">{{ JMS_TITLE }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="font-size: 12px;color: #999999;letter-spacing: 0;line-height: 18px;margin-top: 18px">
|
<div class="contact-form col-md-10 col-md-offset-1">
|
||||||
{% trans 'Welcome back, please enter username and password to login' %}
|
<form id="login-form" action="" method="post" role="form" novalidate="novalidate">
|
||||||
</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 %}
|
{% 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 %}
|
{% if form.non_field_errors %}
|
||||||
{% if form.challenge %}
|
{{ form.non_field_errors.as_text }}
|
||||||
<div style="height: 50px;color: red;line-height: 17px;">
|
{% endif %}
|
||||||
{% else %}
|
</p>
|
||||||
<div style="height: 70px;color: red;line-height: 17px;">
|
{% else %}
|
||||||
|
<p class="welcome-message">
|
||||||
|
{% trans 'Welcome back, please enter username and password to login' %}
|
||||||
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p class="red-fonts">{{ form.non_field_errors.as_text }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
{% elif form.errors.captcha %}
|
|
||||||
<p class="red-fonts">{% trans 'Captcha invalid' %}</p>
|
|
||||||
{% else %}
|
|
||||||
<div style="height: 50px"></div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="form-group">
|
{% bootstrap_field form.username show_label=False %}
|
||||||
<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">
|
<div class="form-group">
|
||||||
<input type="password" class="form-control" id="password" placeholder="{% trans 'Password' %}" required="">
|
<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 }}">
|
<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>
|
</div>
|
||||||
{% if form.challenge %}
|
{% if form.challenge %}
|
||||||
<div class="form-group">
|
{% bootstrap_field form.challenge show_label=False %}
|
||||||
<input type="challenge" class="form-control" id="challenge" name="{{ form.challenge.html_name }}" placeholder="{% trans 'MFA code' %}" >
|
{% elif form.captcha %}
|
||||||
{% if form.errors.challenge %}
|
<div class="captch-field">
|
||||||
<div class="help-block field-error">
|
{% bootstrap_field form.captcha show_label=False %}
|
||||||
<p class="red-fonts">{{ form.errors.challenge.as_text }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
<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 %}
|
{% endif %}
|
||||||
{% if form.captcha %}
|
|
||||||
<div class="form-group" style="height: 50px;margin-bottom: 0;font-size: 13px">
|
|
||||||
{{ form.captcha }}
|
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
<div class="col-md-6">
|
||||||
<div class="form-group" style="height: 25px;margin-bottom: 0;font-size: 13px"></div>
|
<a id="forgot_password" href="{% url 'authentication:forgot-password' %}" style="float: right">
|
||||||
{% endif %}
|
<small>{% trans 'Forgot password' %}?</small>
|
||||||
<div class="form-group" style="margin-top: 10px">
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="">
|
||||||
<button type="submit" class="btn btn-transparent" onclick="doLogin();return false;">{% trans 'Login' %}</button>
|
<button type="submit" class="btn btn-transparent" onclick="doLogin();return false;">{% trans 'Login' %}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -141,51 +180,42 @@
|
||||||
<div style="display: inline-block; float: left">
|
<div style="display: inline-block; float: left">
|
||||||
<b class="text-muted text-left" style="margin-right: 10px">{% trans "More login options" %}</b>
|
<b class="text-muted text-left" style="margin-right: 10px">{% trans "More login options" %}</b>
|
||||||
{% if AUTH_OPENID %}
|
{% if AUTH_OPENID %}
|
||||||
<a href="{% url 'authentication:openid:login' %}">
|
<a href="{% url 'authentication:openid:login' %}" class="more-login-item">
|
||||||
<i class="fa fa-openid"></i> {% trans 'OpenID' %}
|
<i class="fa fa-openid"></i> {% trans 'OpenID' %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if AUTH_CAS %}
|
{% if AUTH_CAS %}
|
||||||
<a href="{% url 'authentication:cas:cas-login' %}">
|
<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' %}
|
<i class="fa"><img src="{{ LOGIN_CAS_LOGO_URL }}" height="13" width="13"></i> {% trans 'CAS' %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center" style="display: inline-block; float: right">
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="text-center" style="display: inline-block;">
|
<div class="text-center" style="display: inline-block;">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a id="forgot_password" href="{% url 'authentication:forgot-password' %}">
|
|
||||||
<small>{% trans 'Forgot password' %}?</small>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
<script type="text/javascript" src="/static/js/plugins/jsencrypt/jsencrypt.min.js"></script>
|
<script type="text/javascript" src="/static/js/plugins/jsencrypt/jsencrypt.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
function encryptLoginPassword(password, rsaPublicKey){
|
function encryptLoginPassword(password, rsaPublicKey) {
|
||||||
var jsencrypt = new JSEncrypt(); //加密对象
|
var jsencrypt = new JSEncrypt(); //加密对象
|
||||||
jsencrypt.setPublicKey(rsaPublicKey); // 设置密钥
|
jsencrypt.setPublicKey(rsaPublicKey); // 设置密钥
|
||||||
return jsencrypt.encrypt(password); //加密
|
return jsencrypt.encrypt(password); //加密
|
||||||
}
|
}
|
||||||
|
|
||||||
function doLogin() {
|
function doLogin() {
|
||||||
//公钥加密
|
//公钥加密
|
||||||
var rsaPublicKey = "{{ rsa_public_key }}"
|
var rsaPublicKey = "{{ rsa_public_key }}"
|
||||||
var password =$('#password').val(); //明文密码
|
var password = $('#password').val(); //明文密码
|
||||||
var passwordEncrypted = encryptLoginPassword(password, rsaPublicKey)
|
var passwordEncrypted = encryptLoginPassword(password, rsaPublicKey)
|
||||||
$('#password-hidden').val(passwordEncrypted); //返回给密码输入input
|
$('#password-hidden').val(passwordEncrypted); //返回给密码输入input
|
||||||
$('#contact-form').submit();//post提交
|
$('#login-form').submit();//post提交
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
|
|
@ -122,6 +122,13 @@ class UserLoginGuardView(mixins.AuthMixin, RedirectView):
|
||||||
url = "%s?%s" % (url, args)
|
url = "%s?%s" % (url, args)
|
||||||
return url
|
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):
|
def get_redirect_url(self, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
user = self.check_user_auth_if_need()
|
user = self.check_user_auth_if_need()
|
||||||
|
@ -138,7 +145,7 @@ class UserLoginGuardView(mixins.AuthMixin, RedirectView):
|
||||||
except errors.PasswdTooSimple as e:
|
except errors.PasswdTooSimple as e:
|
||||||
return e.url
|
return e.url
|
||||||
else:
|
else:
|
||||||
auth_login(self.request, user)
|
self.login_it(user)
|
||||||
self.send_auth_signal(success=True, user=user)
|
self.send_auth_signal(success=True, user=user)
|
||||||
self.clear_auth_mark()
|
self.clear_auth_mark()
|
||||||
url = redirect_user_first_login_or_index(
|
url = redirect_user_first_login_or_index(
|
||||||
|
|
|
@ -285,6 +285,8 @@ class Config(dict):
|
||||||
'ONLY_ALLOW_EXIST_USER_AUTH': False,
|
'ONLY_ALLOW_EXIST_USER_AUTH': False,
|
||||||
'ONLY_ALLOW_AUTH_FROM_SOURCE': True,
|
'ONLY_ALLOW_AUTH_FROM_SOURCE': True,
|
||||||
'DISK_CHECK_ENABLED': True,
|
'DISK_CHECK_ENABLED': True,
|
||||||
|
'SESSION_SAVE_EVERY_REQUEST': True,
|
||||||
|
'SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
def compatible_auth_openid_of_key(self):
|
def compatible_auth_openid_of_key(self):
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
from django.templatetags.static import static
|
from django.templatetags.static import static
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
|
|
||||||
def jumpserver_processor(request):
|
def jumpserver_processor(request):
|
||||||
|
@ -14,7 +14,7 @@ def jumpserver_processor(request):
|
||||||
'LOGIN_IMAGE_URL': static('img/login_image.png'),
|
'LOGIN_IMAGE_URL': static('img/login_image.png'),
|
||||||
'FAVICON_URL': static('img/facio.ico'),
|
'FAVICON_URL': static('img/facio.ico'),
|
||||||
'LOGIN_CAS_LOGO_URL': static('img/login_cas_logo.png'),
|
'LOGIN_CAS_LOGO_URL': static('img/login_cas_logo.png'),
|
||||||
'JMS_TITLE': 'JumpServer',
|
'JMS_TITLE': _('JumpServer Open Source PAM'),
|
||||||
'VERSION': settings.VERSION,
|
'VERSION': settings.VERSION,
|
||||||
'COPYRIGHT': 'FIT2CLOUD 飞致云' + ' © 2014-2021',
|
'COPYRIGHT': 'FIT2CLOUD 飞致云' + ' © 2014-2021',
|
||||||
'SECURITY_COMMAND_EXECUTION': settings.SECURITY_COMMAND_EXECUTION,
|
'SECURITY_COMMAND_EXECUTION': settings.SECURITY_COMMAND_EXECUTION,
|
||||||
|
|
|
@ -120,7 +120,10 @@ LOGIN_URL = reverse_lazy('authentication:login')
|
||||||
SESSION_COOKIE_DOMAIN = CONFIG.SESSION_COOKIE_DOMAIN
|
SESSION_COOKIE_DOMAIN = CONFIG.SESSION_COOKIE_DOMAIN
|
||||||
CSRF_COOKIE_DOMAIN = CONFIG.CSRF_COOKIE_DOMAIN
|
CSRF_COOKIE_DOMAIN = CONFIG.CSRF_COOKIE_DOMAIN
|
||||||
SESSION_COOKIE_AGE = CONFIG.SESSION_COOKIE_AGE
|
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_ENGINE = 'redis_sessions.session'
|
||||||
SESSION_REDIS = {
|
SESSION_REDIS = {
|
||||||
'host': CONFIG.REDIS_HOST,
|
'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;
|
background-color: transparent;
|
||||||
border: 1px solid #dedede;
|
border: 1px solid #dedede;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
height: 45px !important;
|
|
||||||
color: #0c0c0c;
|
color: #0c0c0c;
|
||||||
height: 30px;
|
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;
|
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;
|
background-color: transparent;
|
||||||
border: 1px solid #dedede;
|
border: 1px solid #dedede;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
height: 45px !important;
|
|
||||||
color: #0c0c0c;
|
color: #0c0c0c;
|
||||||
height: 38px;
|
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;
|
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 {
|
.btn-transparent {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border: 1px solid #fff;
|
border: 1px solid #1ab394;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
padding: 14px 35px;
|
padding: 10px 30px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
border-radius: 40px;
|
border-radius: 5px;
|
||||||
background: #259980;
|
background: #259980;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,12 +66,6 @@ class UserProfileApi(generics.RetrieveUpdateAPIView):
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
return self.request.user
|
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):
|
class UserPasswordApi(generics.RetrieveUpdateAPIView):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
|
|
|
@ -3,6 +3,14 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
|
<style>
|
||||||
|
.captcha {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
#id_captcha_1 {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block html_title %}{% trans 'Forgot password' %}{% endblock %}
|
{% block html_title %}{% trans 'Forgot password' %}{% endblock %}
|
||||||
{% block title %} {% trans 'Forgot password' %}?{% endblock %}
|
{% block title %} {% trans 'Forgot password' %}?{% endblock %}
|
||||||
|
|
Loading…
Reference in New Issue