Commit 517c6822 authored by ibuler's avatar ibuler

[Update] 修改登录路基

parent 458bee9a
import uuid import uuid
from django.db import models from django.db import models
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework.authtoken.models import Token from rest_framework.authtoken.models import Token
from django.conf import settings from django.conf import settings
from common.mixins.models import CommonModelMixin from common.mixins.models import CommonModelMixin
from common.utils import get_object_or_none, get_request_ip, get_ip_city
class AccessKey(models.Model): class AccessKey(models.Model):
...@@ -42,3 +44,32 @@ class LoginConfirmSetting(CommonModelMixin): ...@@ -42,3 +44,32 @@ class LoginConfirmSetting(CommonModelMixin):
reviewers = models.ManyToManyField('users.User', verbose_name=_("Reviewers"), related_name=_("review_login_confirmation_settings")) reviewers = models.ManyToManyField('users.User', verbose_name=_("Reviewers"), related_name=_("review_login_confirmation_settings"))
is_active = models.BooleanField(default=True, verbose_name=_("Is active")) 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)
{% 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 = [ ...@@ -16,5 +16,7 @@ urlpatterns = [
# login # login
path('login/', views.UserLoginView.as_view(), name='login'), path('login/', views.UserLoginView.as_view(), name='login'),
path('login/otp/', views.UserLoginOtpView.as_view(), name='login-otp'), 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'), path('logout/', views.UserLogoutView.as_view(), name='logout'),
] ]
...@@ -12,13 +12,12 @@ from django.utils.translation import ugettext as _ ...@@ -12,13 +12,12 @@ from django.utils.translation import ugettext as _
from django.views.decorators.cache import never_cache from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect from django.views.decorators.csrf import csrf_protect
from django.views.decorators.debug import sensitive_post_parameters 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.views.generic.edit import FormView
from django.conf import settings from django.conf import settings
from common.utils import get_request_ip from common.utils import get_request_ip
from users.models import User from users.models import User
from audits.models import UserLoginLog as LoginLog
from users.utils import ( from users.utils import (
check_otp_code, is_block_login, clean_failed_count, get_user_or_tmp_user, check_otp_code, is_block_login, clean_failed_count, get_user_or_tmp_user,
set_tmp_user_to_cache, increase_login_failed_count, set_tmp_user_to_cache, increase_login_failed_count,
...@@ -31,6 +30,7 @@ from .. import const ...@@ -31,6 +30,7 @@ from .. import const
__all__ = [ __all__ = [
'UserLoginView', 'UserLoginOtpView', 'UserLogoutView', 'UserLoginView', 'UserLoginOtpView', 'UserLogoutView',
'UserLoginContinueView', 'UserLoginWaitConfirmView',
] ]
...@@ -40,7 +40,6 @@ __all__ = [ ...@@ -40,7 +40,6 @@ __all__ = [
class UserLoginView(FormView): class UserLoginView(FormView):
form_class = forms.UserLoginForm form_class = forms.UserLoginForm
form_class_captcha = forms.UserLoginCaptchaForm form_class_captcha = forms.UserLoginCaptchaForm
redirect_field_name = 'next'
key_prefix_captcha = "_LOGIN_INVALID_{}" key_prefix_captcha = "_LOGIN_INVALID_{}"
def get_template_names(self): def get_template_names(self):
...@@ -52,7 +51,7 @@ class UserLoginView(FormView): ...@@ -52,7 +51,7 @@ class UserLoginView(FormView):
if not License.has_valid_license(): if not License.has_valid_license():
return template_name return template_name
template_name = 'authentication/new_login.html' template_name = 'authentication/xpack_login.html'
return template_name return template_name
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
...@@ -91,7 +90,8 @@ class UserLoginView(FormView): ...@@ -91,7 +90,8 @@ class UserLoginView(FormView):
ip = get_request_ip(self.request) ip = get_request_ip(self.request)
# 登陆成功,清除缓存计数 # 登陆成功,清除缓存计数
clean_failed_count(username, ip) 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): def form_invalid(self, form):
# write login failed log # write login failed log
...@@ -111,6 +111,11 @@ class UserLoginView(FormView): ...@@ -111,6 +111,11 @@ class UserLoginView(FormView):
form._errors = old_form.errors form._errors = old_form.errors
return super().form_invalid(form) 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): def get_form_class(self):
ip = get_request_ip(self.request) ip = get_request_ip(self.request)
if cache.get(self.key_prefix_captcha.format(ip)): if cache.get(self.key_prefix_captcha.format(ip)):
...@@ -118,21 +123,6 @@ class UserLoginView(FormView): ...@@ -118,21 +123,6 @@ class UserLoginView(FormView):
else: else:
return self.form_class 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): def get_context_data(self, **kwargs):
context = { context = {
'demo_mode': os.environ.get("DEMO_MODE"), 'demo_mode': os.environ.get("DEMO_MODE"),
...@@ -141,15 +131,6 @@ class UserLoginView(FormView): ...@@ -141,15 +131,6 @@ class UserLoginView(FormView):
kwargs.update(context) kwargs.update(context)
return super().get_context_data(**kwargs) 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): class UserLoginOtpView(FormView):
template_name = 'authentication/login_otp.html' template_name = 'authentication/login_otp.html'
...@@ -162,9 +143,8 @@ class UserLoginOtpView(FormView): ...@@ -162,9 +143,8 @@ class UserLoginOtpView(FormView):
otp_secret_key = user.otp_secret_key otp_secret_key = user.otp_secret_key
if check_otp_code(otp_secret_key, otp_code): if check_otp_code(otp_secret_key, otp_code):
auth_login(self.request, user) self.request.session['auth_otp'] = '1'
self.send_auth_signal(success=True, user=user) return UserLoginView.redirect_to_continue_view()
return redirect(self.get_success_url())
else: else:
self.send_auth_signal( self.send_auth_signal(
success=False, username=user.username, success=False, username=user.username,
...@@ -175,8 +155,40 @@ class UserLoginOtpView(FormView): ...@@ -175,8 +155,40 @@ class UserLoginOtpView(FormView):
) )
return super().form_invalid(form) return super().form_invalid(form)
def get_success_url(self): def send_auth_signal(self, success=True, user=None, username='', reason=''):
return redirect_user_first_login_or_index(self.request, self.redirect_field_name) 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=''): def send_auth_signal(self, success=True, user=None, username='', reason=''):
if success: if success:
...@@ -188,6 +200,13 @@ class UserLoginOtpView(FormView): ...@@ -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') @method_decorator(never_cache, name='dispatch')
class UserLogoutView(TemplateView): class UserLogoutView(TemplateView):
template_name = 'flash_message_standalone.html' template_name = 'flash_message_standalone.html'
......
...@@ -10,8 +10,9 @@ class Order(CommonModelMixin): ...@@ -10,8 +10,9 @@ class Order(CommonModelMixin):
('rejected', _("Rejected")), ('rejected', _("Rejected")),
('pending', _("Pending")) ('pending', _("Pending"))
) )
TYPE_LOGIN_REQUEST = 'login_request'
TYPE_CHOICES = ( 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 = 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")) user_display = models.CharField(max_length=128, verbose_name=_("User display name"))
...@@ -22,7 +23,10 @@ class Order(CommonModelMixin): ...@@ -22,7 +23,10 @@ class Order(CommonModelMixin):
assignees_display = models.CharField(max_length=128, verbose_name=_("Assignees display name"), blank=True) assignees_display = models.CharField(max_length=128, verbose_name=_("Assignees display name"), blank=True)
type = models.CharField(choices=TYPE_CHOICES, max_length=64) 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: class Meta:
ordering = ('date_created',) ordering = ('date_created',)
......
...@@ -10,7 +10,9 @@ from django.conf import settings ...@@ -10,7 +10,9 @@ from django.conf import settings
from django.contrib.auth.hashers import make_password from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.core.cache import cache from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone from django.utils import timezone
from django.shortcuts import reverse from django.shortcuts import reverse
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment