mirror of https://github.com/jumpserver/jumpserver
[Update] 修改登录路基
parent
458bee9a19
commit
517c682201
|
@ -1,10 +1,12 @@
|
|||
import uuid
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework.authtoken.models import Token
|
||||
from django.conf import settings
|
||||
|
||||
from common.mixins.models import CommonModelMixin
|
||||
from common.utils import get_object_or_none, get_request_ip, get_ip_city
|
||||
|
||||
|
||||
class AccessKey(models.Model):
|
||||
|
@ -42,3 +44,32 @@ class LoginConfirmSetting(CommonModelMixin):
|
|||
reviewers = models.ManyToManyField('users.User', verbose_name=_("Reviewers"), related_name=_("review_login_confirmation_settings"))
|
||||
is_active = models.BooleanField(default=True, verbose_name=_("Is active"))
|
||||
|
||||
@classmethod
|
||||
def get_user_confirm_setting(cls, user):
|
||||
return get_object_or_none(cls, user=user)
|
||||
|
||||
def create_confirm_order(self, request=None):
|
||||
from orders.models import Order
|
||||
title = _('User login request confirm: {}'.format(self.user))
|
||||
if request:
|
||||
remote_addr = get_request_ip(request)
|
||||
city = get_ip_city(remote_addr)
|
||||
body = _("User: {}\nIP: {}\nCity: {}\nDate: {}\n").format(
|
||||
self.user, remote_addr, city, timezone.now()
|
||||
)
|
||||
else:
|
||||
body = ''
|
||||
reviewer = self.reviewers.all()
|
||||
reviewer_names = ','.join([u.name for u in reviewer])
|
||||
order = Order.objects.create(
|
||||
user=self.user, user_display=str(self.user),
|
||||
title=title, body=body,
|
||||
assignees_display=reviewer_names,
|
||||
type=Order.TYPE_LOGIN_REQUEST,
|
||||
)
|
||||
order.assignees.set(reviewer)
|
||||
return order
|
||||
|
||||
def __str__(self):
|
||||
return '{} confirm'.format(self.user.username)
|
||||
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
{% load i18n %}
|
||||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>{{ title }}</title>
|
||||
|
||||
{% include '_head_css_js.html' %}
|
||||
<link href="{% static "css/jumpserver.css" %}" rel="stylesheet">
|
||||
<script type="text/javascript"
|
||||
src="{% url 'javascript-catalog' %}"></script>
|
||||
<script src="{% static "js/jumpserver.js" %}"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="gray-bg">
|
||||
<div class="passwordBox2 animated fadeInDown">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="ibox-content">
|
||||
<div>
|
||||
<img src="{{ LOGO_URL }}" style="margin: auto" width="82" height="82">
|
||||
<h2 style="display: inline">
|
||||
{{ JMS_TITLE }}
|
||||
</h2>
|
||||
</div>
|
||||
<p></p>
|
||||
<div class="alert alert-success" id="messages">
|
||||
Wait for Guanghongwei confirm, You also can copy link to her/his <br/>
|
||||
Don't close ....
|
||||
</div>
|
||||
<div class="progress progress-bar-default">
|
||||
<div style="width: 43%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="43" role="progressbar" class="progress-bar">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3">
|
||||
<a href="{{ redirect_url }}" class="btn btn-primary block full-width m-b">
|
||||
{% trans 'Refresh' %}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<a href="{{ redirect_url }}" class="btn btn-primary block full-width m-b">
|
||||
{% trans 'Copy link' %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{% include '_copyright.html' %}
|
||||
</div>
|
||||
<div class="col-md-6 text-right">
|
||||
<small>2014-2019</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
var time = '{{ interval }}';
|
||||
if (!time) {
|
||||
time = 5;
|
||||
} else {
|
||||
time = parseInt(time);
|
||||
}
|
||||
|
||||
function redirect_page() {
|
||||
if (time >= 0) {
|
||||
var messages = '{{ messages|safe }}, <b>' + time + '</b> ...';
|
||||
$('#messages').html(messages);
|
||||
time--;
|
||||
setTimeout(redirect_page, 1000);
|
||||
} else {
|
||||
window.location.href = "{{ redirect_url }}";
|
||||
}
|
||||
}
|
||||
{% if auto_redirect %}
|
||||
window.onload = redirect_page;
|
||||
{% endif %}
|
||||
</script>
|
||||
</html>
|
|
@ -16,5 +16,7 @@ urlpatterns = [
|
|||
# login
|
||||
path('login/', views.UserLoginView.as_view(), name='login'),
|
||||
path('login/otp/', views.UserLoginOtpView.as_view(), name='login-otp'),
|
||||
path('login/continue/', views.UserLoginContinueView.as_view(), name='login-continue'),
|
||||
path('login/wait/', views.UserLoginWaitConfirmView.as_view(), name='login-wait'),
|
||||
path('logout/', views.UserLogoutView.as_view(), name='logout'),
|
||||
]
|
||||
|
|
|
@ -12,13 +12,12 @@ from django.utils.translation import ugettext as _
|
|||
from django.views.decorators.cache import never_cache
|
||||
from django.views.decorators.csrf import csrf_protect
|
||||
from django.views.decorators.debug import sensitive_post_parameters
|
||||
from django.views.generic.base import TemplateView
|
||||
from django.views.generic.base import TemplateView, View, RedirectView
|
||||
from django.views.generic.edit import FormView
|
||||
from django.conf import settings
|
||||
|
||||
from common.utils import get_request_ip
|
||||
from users.models import User
|
||||
from audits.models import UserLoginLog as LoginLog
|
||||
from users.utils import (
|
||||
check_otp_code, is_block_login, clean_failed_count, get_user_or_tmp_user,
|
||||
set_tmp_user_to_cache, increase_login_failed_count,
|
||||
|
@ -31,6 +30,7 @@ from .. import const
|
|||
|
||||
__all__ = [
|
||||
'UserLoginView', 'UserLoginOtpView', 'UserLogoutView',
|
||||
'UserLoginContinueView', 'UserLoginWaitConfirmView',
|
||||
]
|
||||
|
||||
|
||||
|
@ -40,7 +40,6 @@ __all__ = [
|
|||
class UserLoginView(FormView):
|
||||
form_class = forms.UserLoginForm
|
||||
form_class_captcha = forms.UserLoginCaptchaForm
|
||||
redirect_field_name = 'next'
|
||||
key_prefix_captcha = "_LOGIN_INVALID_{}"
|
||||
|
||||
def get_template_names(self):
|
||||
|
@ -52,7 +51,7 @@ class UserLoginView(FormView):
|
|||
if not License.has_valid_license():
|
||||
return template_name
|
||||
|
||||
template_name = 'authentication/new_login.html'
|
||||
template_name = 'authentication/xpack_login.html'
|
||||
return template_name
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
@ -91,7 +90,8 @@ class UserLoginView(FormView):
|
|||
ip = get_request_ip(self.request)
|
||||
# 登陆成功,清除缓存计数
|
||||
clean_failed_count(username, ip)
|
||||
return redirect(self.get_success_url())
|
||||
self.request.session['auth_password'] = '1'
|
||||
return self.redirect_to_continue_view()
|
||||
|
||||
def form_invalid(self, form):
|
||||
# write login failed log
|
||||
|
@ -111,6 +111,11 @@ class UserLoginView(FormView):
|
|||
form._errors = old_form.errors
|
||||
return super().form_invalid(form)
|
||||
|
||||
@staticmethod
|
||||
def redirect_to_continue_view():
|
||||
continue_url = reverse('authentication:login-continue')
|
||||
return redirect(continue_url)
|
||||
|
||||
def get_form_class(self):
|
||||
ip = get_request_ip(self.request)
|
||||
if cache.get(self.key_prefix_captcha.format(ip)):
|
||||
|
@ -118,21 +123,6 @@ class UserLoginView(FormView):
|
|||
else:
|
||||
return self.form_class
|
||||
|
||||
def get_success_url(self):
|
||||
user = get_user_or_tmp_user(self.request)
|
||||
|
||||
if user.otp_enabled and user.otp_secret_key:
|
||||
# 1,2,mfa_setting & T
|
||||
return reverse('authentication:login-otp')
|
||||
elif user.otp_enabled and not user.otp_secret_key:
|
||||
# 1,2,mfa_setting & F
|
||||
return reverse('users:user-otp-enable-authentication')
|
||||
elif not user.otp_enabled:
|
||||
# 0 & T,F
|
||||
auth_login(self.request, user)
|
||||
self.send_auth_signal(success=True, user=user)
|
||||
return redirect_user_first_login_or_index(self.request, self.redirect_field_name)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'demo_mode': os.environ.get("DEMO_MODE"),
|
||||
|
@ -141,15 +131,6 @@ class UserLoginView(FormView):
|
|||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def send_auth_signal(self, success=True, user=None, username='', reason=''):
|
||||
if success:
|
||||
post_auth_success.send(sender=self.__class__, user=user, request=self.request)
|
||||
else:
|
||||
post_auth_failed.send(
|
||||
sender=self.__class__, username=username,
|
||||
request=self.request, reason=reason
|
||||
)
|
||||
|
||||
|
||||
class UserLoginOtpView(FormView):
|
||||
template_name = 'authentication/login_otp.html'
|
||||
|
@ -162,9 +143,8 @@ class UserLoginOtpView(FormView):
|
|||
otp_secret_key = user.otp_secret_key
|
||||
|
||||
if check_otp_code(otp_secret_key, otp_code):
|
||||
auth_login(self.request, user)
|
||||
self.send_auth_signal(success=True, user=user)
|
||||
return redirect(self.get_success_url())
|
||||
self.request.session['auth_otp'] = '1'
|
||||
return UserLoginView.redirect_to_continue_view()
|
||||
else:
|
||||
self.send_auth_signal(
|
||||
success=False, username=user.username,
|
||||
|
@ -175,8 +155,40 @@ class UserLoginOtpView(FormView):
|
|||
)
|
||||
return super().form_invalid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return redirect_user_first_login_or_index(self.request, self.redirect_field_name)
|
||||
def send_auth_signal(self, success=True, user=None, username='', reason=''):
|
||||
if success:
|
||||
post_auth_success.send(sender=self.__class__, user=user, request=self.request)
|
||||
else:
|
||||
post_auth_failed.send(
|
||||
sender=self.__class__, username=username,
|
||||
request=self.request, reason=reason
|
||||
)
|
||||
|
||||
|
||||
class UserLoginContinueView(RedirectView):
|
||||
redirect_field_name = 'next'
|
||||
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
if not self.request.session.get('auth_password'):
|
||||
return reverse('authentication:login')
|
||||
|
||||
user = get_user_or_tmp_user(self.request)
|
||||
if user.otp_enabled and user.otp_secret_key and \
|
||||
not self.request.session.get('auth_otp'):
|
||||
return reverse('authentication:login-otp')
|
||||
|
||||
self.login_success(user)
|
||||
if user.otp_enabled and not user.otp_secret_key:
|
||||
# 1,2,mfa_setting & F
|
||||
return reverse('users:user-otp-enable-authentication')
|
||||
url = redirect_user_first_login_or_index(
|
||||
self.request, self.redirect_field_name
|
||||
)
|
||||
return url
|
||||
|
||||
def login_success(self, user):
|
||||
auth_login(self.request, user)
|
||||
self.send_auth_signal(success=True, user=user)
|
||||
|
||||
def send_auth_signal(self, success=True, user=None, username='', reason=''):
|
||||
if success:
|
||||
|
@ -188,6 +200,13 @@ class UserLoginOtpView(FormView):
|
|||
)
|
||||
|
||||
|
||||
class UserLoginWaitConfirmView(TemplateView):
|
||||
template_name = 'authentication/login_wait_confirm.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
@method_decorator(never_cache, name='dispatch')
|
||||
class UserLogoutView(TemplateView):
|
||||
template_name = 'flash_message_standalone.html'
|
||||
|
|
|
@ -10,8 +10,9 @@ class Order(CommonModelMixin):
|
|||
('rejected', _("Rejected")),
|
||||
('pending', _("Pending"))
|
||||
)
|
||||
TYPE_LOGIN_REQUEST = 'login_request'
|
||||
TYPE_CHOICES = (
|
||||
('login_request', _("Login request")),
|
||||
(TYPE_LOGIN_REQUEST, _("Login request")),
|
||||
)
|
||||
user = models.ForeignKey('users.User', on_delete=models.SET_NULL, null=True, related_name='orders', verbose_name=_("User"))
|
||||
user_display = models.CharField(max_length=128, verbose_name=_("User display name"))
|
||||
|
@ -22,7 +23,10 @@ class Order(CommonModelMixin):
|
|||
assignees_display = models.CharField(max_length=128, verbose_name=_("Assignees display name"), blank=True)
|
||||
|
||||
type = models.CharField(choices=TYPE_CHOICES, max_length=64)
|
||||
status = models.CharField(choices=STATUS_CHOICES, max_length=16)
|
||||
status = models.CharField(choices=STATUS_CHOICES, max_length=16, default='pending')
|
||||
|
||||
def __str__(self):
|
||||
return '{}: {}'.format(self.user_display, self.title)
|
||||
|
||||
class Meta:
|
||||
ordering = ('date_created',)
|
||||
|
|
|
@ -10,7 +10,9 @@ from django.conf import settings
|
|||
from django.contrib.auth.hashers import make_password
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import models
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
from django.shortcuts import reverse
|
||||
|
|
Loading…
Reference in New Issue