[Update] 添加解除用户登录限制功能

pull/1533/head
BaiJiangJie 2018-07-16 12:13:13 +08:00
parent 1182313c1a
commit 812078331e
7 changed files with 49 additions and 14 deletions

Binary file not shown.

View File

@ -2774,11 +2774,11 @@ msgstr "发送重置密钥邮件"
#: users/templates/users/user_detail.html:186
#: users/templates/users/user_detail.html:444
msgid "Unblock user"
msgstr "解锁用户"
msgstr "解除登录限制"
#: users/templates/users/user_detail.html:189
msgid "Unblock"
msgstr "解"
msgstr "解"
#: users/templates/users/user_detail.html:303
msgid "Goto profile page enable MFA"
@ -2820,7 +2820,7 @@ msgstr "ssh密钥"
#: users/templates/users/user_detail.html:454
msgid "After unlocking the user, the user can log in normally."
msgstr "解锁用户后,此用户即可正常登录"
msgstr "解除用户登录限制后,此用户即可正常登录"
#: users/templates/users/user_group_create_update.html:31
msgid "Cancel"
@ -3181,7 +3181,7 @@ msgid "MFA disable success, return login page"
msgstr "MFA 解绑成功,返回登录页面"
#~ msgid "Unblock user successfully. "
#~ msgstr "解锁用户成功"
#~ msgstr "解除登录限制成功"
#~ msgid "Clear"
#~ msgstr "清除"

View File

@ -100,12 +100,15 @@ class UserUnblockPKApi(generics.UpdateAPIView):
permission_classes = (IsSuperUser,)
serializer_class = UserSerializer
key_prefix_limit = "_LOGIN_LIMIT_{}_{}"
key_prefix_block = "_LOGIN_BLOCK_{}"
def perform_update(self, serializer):
user = self.get_object()
username = user.username if user else ''
key_limit = self.key_prefix_limit.format(username, '*')
key_block = self.key_prefix_block.format(username)
cache.delete_pattern(key_limit)
cache.delete(key_block)
class UserGroupViewSet(IDInFilterMixin, BulkModelViewSet):
@ -210,6 +213,7 @@ class UserAuthApi(APIView):
permission_classes = (AllowAny,)
serializer_class = UserSerializer
key_prefix_limit = "_LOGIN_LIMIT_{}_{}"
key_prefix_block = "_LOGIN_BLOCK_{}"
def post(self, request):
# limit login
@ -217,6 +221,7 @@ class UserAuthApi(APIView):
ip = request.data.get('remote_addr', None)
ip = ip if ip else get_login_ip(request)
key_limit = self.key_prefix_limit.format(username, ip)
key_block = self.key_prefix_block.format(username)
if is_block_login(key_limit):
msg = _("Log in frequently and try again later")
return Response({'msg': msg}, status=401)
@ -231,7 +236,7 @@ class UserAuthApi(APIView):
}
self.write_login_log(request, data)
set_user_login_failed_count_to_cache(key_limit)
set_user_login_failed_count_to_cache(key_limit, key_block)
return Response({'msg': msg}, status=401)
if not user.otp_enabled:

View File

@ -182,7 +182,7 @@
</span>
</td>
</tr>
<tr>
<tr id="id_unblock_user" style="{% if not unblock %}display:none{% endif %}">
<td>{% trans 'Unblock user' %}</td>
<td>
<span class="pull-right">
@ -283,7 +283,7 @@ $(document).ready(function() {
.on('select2:unselect', function(evt) {
var data = evt.params.data;
delete jumpserver.nodes_selected[data.id];
})
});
})
.on('click', '#is_active', function() {
var the_url = "{% url 'api-users:user-detail' pk=user_object.id %}";
@ -301,7 +301,7 @@ $(document).ready(function() {
.on('click', '#force_enable_otp', function() {
{% if request.user == user_object %}
toastr.error("{% trans 'Goto profile page enable MFA' %}");
return
return;
{% endif %}
var the_url = "{% url 'api-users:user-detail' pk=user_object.id %}";
@ -441,7 +441,15 @@ $(document).ready(function() {
var body = {};
var success = function() {
var msg = "{% trans "Success" %}";
swal("{% trans 'Unblock user' %}", msg, "success");
{#swal("{% trans 'Unblock user' %}", msg, "success");#}
swal({
title: "{% trans 'Unblock user' %}",
text: msg,
type: "success"
}, function() {
location.reload()
}
);
};
APIUpdateAttr({
url: the_url,
@ -460,7 +468,6 @@ $(document).ready(function() {
}, function() {
doReset();
});
})
</script>
{% endblock %}

View File

@ -333,7 +333,7 @@ def check_password_rules(password):
return bool(match_obj)
def set_user_login_failed_count_to_cache(key_limit):
def set_user_login_failed_count_to_cache(key_limit, key_block):
count = cache.get(key_limit)
count = count + 1 if count else 1
@ -343,6 +343,15 @@ def set_user_login_failed_count_to_cache(key_limit):
limit_time = setting_limit_time.cleaned_value if setting_limit_time \
else settings.DEFAULT_LOGIN_LIMIT_TIME
setting_limit_count = Setting.objects.filter(
name='SECURITY_LOGIN_LIMIT_COUNT'
).first()
limit_count = setting_limit_count.cleaned_value if setting_limit_count \
else settings.DEFAULT_LOGIN_LIMIT_COUNT
if count >= limit_count:
cache.set(key_block, 1, int(limit_time)*60)
cache.set(key_limit, count, int(limit_time)*60)
@ -357,3 +366,9 @@ def is_block_login(key_limit):
if count and count >= limit_count:
return True
def is_need_unblock(key_block):
if not cache.get(key_block):
return False
return True

View File

@ -51,6 +51,7 @@ class UserLoginView(FormView):
redirect_field_name = 'next'
key_prefix_captcha = "_LOGIN_INVALID_{}"
key_prefix_limit = "_LOGIN_LIMIT_{}_{}"
key_prefix_block = "_LOGIN_BLOCK_{}"
def get(self, request, *args, **kwargs):
if request.user.is_staff:
@ -91,7 +92,8 @@ class UserLoginView(FormView):
# limit user login failed count
ip = get_login_ip(self.request)
key_limit = self.key_prefix_limit.format(username, ip)
set_user_login_failed_count_to_cache(key_limit)
key_block = self.key_prefix_block.format(username)
set_user_login_failed_count_to_cache(key_limit, key_block)
# show captcha
cache.set(self.key_prefix_captcha.format(ip), 1, 3600)

View File

@ -36,7 +36,9 @@ from common.utils import get_logger, get_object_or_none, is_uuid, ssh_key_gen
from common.models import Setting
from .. import forms
from ..models import User, UserGroup
from ..utils import AdminUserRequiredMixin, generate_otp_uri, check_otp_code, get_user_or_tmp_user, get_password_check_rules, check_password_rules
from ..utils import AdminUserRequiredMixin, generate_otp_uri, check_otp_code, \
get_user_or_tmp_user, get_password_check_rules, check_password_rules, \
is_need_unblock
from ..signals import post_user_create
from ..tasks import write_login_log_async
@ -168,13 +170,17 @@ class UserDetailView(AdminUserRequiredMixin, DetailView):
model = User
template_name = 'users/user_detail.html'
context_object_name = "user_object"
key_prefix_block = "_LOGIN_BLOCK_{}"
def get_context_data(self, **kwargs):
user = self.get_object()
key_block = self.key_prefix_block.format(user.username)
groups = UserGroup.objects.exclude(id__in=self.object.groups.all())
context = {
'app': _('Users'),
'action': _('User detail'),
'groups': groups
'groups': groups,
'unblock': is_need_unblock(key_block),
}
kwargs.update(context)
return super().get_context_data(**kwargs)