Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
gjl2004yn
jumpserver
提交
ec8106e4
J
jumpserver
项目概览
gjl2004yn
/
jumpserver
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
jumpserver
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
ec8106e4
编写于
12月 05, 2017
作者:
baltery
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[Feature] 完成登陆日志
上级
a5f97359
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
168 addition
and
17 deletion
+168
-17
apps/jumpserver/views.py
apps/jumpserver/views.py
+0
-1
apps/templates/_nav.html
apps/templates/_nav.html
+1
-1
apps/users/api.py
apps/users/api.py
+2
-3
apps/users/models/authentication.py
apps/users/models/authentication.py
+2
-4
apps/users/templates/users/login_log_list.html
apps/users/templates/users/login_log_list.html
+92
-0
apps/users/urls/views_urls.py
apps/users/urls/views_urls.py
+3
-0
apps/users/utils.py
apps/users/utils.py
+1
-1
apps/users/views/login.py
apps/users/views/login.py
+66
-6
requirements/requirements.txt
requirements/requirements.txt
+1
-1
未找到文件。
apps/jumpserver/views.py
浏览文件 @
ec8106e4
...
@@ -94,7 +94,6 @@ class IndexView(LoginRequiredMixin, TemplateView):
...
@@ -94,7 +94,6 @@ class IndexView(LoginRequiredMixin, TemplateView):
for
asset
in
assets
:
for
asset
in
assets
:
last_login
=
self
.
session_week
.
filter
(
asset
=
asset
[
"asset"
]).
order_by
(
'date_start'
).
last
()
last_login
=
self
.
session_week
.
filter
(
asset
=
asset
[
"asset"
]).
order_by
(
'date_start'
).
last
()
asset
[
'last'
]
=
last_login
asset
[
'last'
]
=
last_login
print
(
asset
)
return
assets
return
assets
def
get_week_top10_user
(
self
):
def
get_week_top10_user
(
self
):
...
...
apps/templates/_nav.html
浏览文件 @
ec8106e4
...
@@ -11,7 +11,7 @@
...
@@ -11,7 +11,7 @@
<ul
class=
"nav nav-second-level active"
>
<ul
class=
"nav nav-second-level active"
>
<li
id=
"user"
><a
href=
"{% url 'users:user-list' %}"
>
{% trans 'User' %}
</a></li>
<li
id=
"user"
><a
href=
"{% url 'users:user-list' %}"
>
{% trans 'User' %}
</a></li>
<li
id=
"user-group"
><a
href=
"{% url 'users:user-group-list' %}"
>
{% trans 'User group' %}
</a></li>
<li
id=
"user-group"
><a
href=
"{% url 'users:user-group-list' %}"
>
{% trans 'User group' %}
</a></li>
<li
id=
"
user-group"
><a
href=
"{% url 'users:user-group
-list' %}"
>
{% trans 'Login logs' %}
</a></li>
<li
id=
"
login-log"
><a
href=
"{% url 'users:login-log
-list' %}"
>
{% trans 'Login logs' %}
</a></li>
</ul>
</ul>
</li>
</li>
<li
id=
"assets"
>
<li
id=
"assets"
>
...
...
apps/users/api.py
浏览文件 @
ec8106e4
...
@@ -164,9 +164,8 @@ class UserAuthApi(APIView):
...
@@ -164,9 +164,8 @@ class UserAuthApi(APIView):
if
user
:
if
user
:
token
=
generate_token
(
request
,
user
)
token
=
generate_token
(
request
,
user
)
write_login_log_async
.
delay
(
write_login_log_async
.
delay
(
user
.
username
,
name
=
user
.
name
,
user
.
username
,
ip
=
login_ip
,
user_agent
=
user_agent
,
login_ip
=
login_ip
,
type
=
login_type
,
user_agent
=
user_agent
,
login_type
=
login_type
)
)
return
Response
({
'token'
:
token
,
'user'
:
user
.
to_json
()})
return
Response
({
'token'
:
token
,
'user'
:
user
.
to_json
()})
else
:
else
:
...
...
apps/users/models/authentication.py
浏览文件 @
ec8106e4
...
@@ -16,8 +16,7 @@ class AccessKey(models.Model):
...
@@ -16,8 +16,7 @@ class AccessKey(models.Model):
default
=
uuid
.
uuid4
,
editable
=
False
)
default
=
uuid
.
uuid4
,
editable
=
False
)
secret
=
models
.
UUIDField
(
verbose_name
=
'AccessKeySecret'
,
secret
=
models
.
UUIDField
(
verbose_name
=
'AccessKeySecret'
,
default
=
uuid
.
uuid4
,
editable
=
False
)
default
=
uuid
.
uuid4
,
editable
=
False
)
user
=
models
.
ForeignKey
(
User
,
verbose_name
=
'User'
,
user
=
models
.
ForeignKey
(
User
,
verbose_name
=
'User'
,
on_delete
=
models
.
CASCADE
,
related_name
=
'access_key'
)
related_name
=
'access_key'
)
def
get_id
(
self
):
def
get_id
(
self
):
return
str
(
self
.
id
)
return
str
(
self
.
id
)
...
@@ -39,8 +38,7 @@ class PrivateToken(Token):
...
@@ -39,8 +38,7 @@ class PrivateToken(Token):
class
LoginLog
(
models
.
Model
):
class
LoginLog
(
models
.
Model
):
LOGIN_TYPE_CHOICE
=
(
LOGIN_TYPE_CHOICE
=
(
(
'W'
,
'Web'
),
(
'W'
,
'Web'
),
(
'ST'
,
'SSH Terminal'
),
(
'T'
,
'Terminal'
),
(
'WT'
,
'Web Terminal'
)
)
)
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
username
=
models
.
CharField
(
max_length
=
20
,
verbose_name
=
_
(
'Username'
))
username
=
models
.
CharField
(
max_length
=
20
,
verbose_name
=
_
(
'Username'
))
...
...
apps/users/templates/users/login_log_list.html
0 → 100644
浏览文件 @
ec8106e4
{% extends '_base_list.html' %}
{% load i18n %}
{% load static %}
{% load common_tags %}
{% block content_left_head %}
<link
href=
"{% static 'css/plugins/datepicker/datepicker3.css' %}"
rel=
"stylesheet"
>
<style>
#search_btn
{
margin-bottom
:
0
;
}
</style>
{% endblock %}
{% block table_search %}
<form
id=
"search_form"
method=
"get"
action=
""
class=
"pull-right form-inline"
>
<div
class=
"form-group"
id=
"date"
>
<div
class=
"input-daterange input-group"
id=
"datepicker"
>
<span
class=
"input-group-addon"
><i
class=
"fa fa-calendar"
></i></span>
<input
type=
"text"
class=
"input-sm form-control"
style=
"width: 100px;"
name=
"date_from"
value=
"{{ date_from }}"
>
<span
class=
"input-group-addon"
>
to
</span>
<input
type=
"text"
class=
"input-sm form-control"
style=
"width: 100px;"
name=
"date_to"
value=
"{{ date_to }}"
>
</div>
</div>
<div
class=
"input-group"
>
<select
class=
"select2 form-control"
name=
"username"
>
<option
value=
""
>
{% trans 'Select user' %}
</option>
{% for u in user_list %}
<option
value=
"{{ u }}"
{%
if
u =
=
username
%}
selected
{%
endif
%}
>
{{ u }}
</option>
{% endfor %}
</select>
</div>
<div
class=
"input-group"
>
<input
type=
"text"
class=
"form-control input-sm"
name=
"keyword"
placeholder=
"Search"
value=
"{{ keyword }}"
>
</div>
<div
class=
"input-group"
>
<div
class=
"input-group-btn"
>
<button
id=
'search_btn'
type=
"submit"
class=
"btn btn-sm btn-primary"
>
搜索
</button>
</div>
</div>
</form>
{% endblock %}
{% block table_head %}
<th
class=
"text-center"
>
{% trans 'ID' %}
</th>
<th
class=
"text-center"
>
{% trans 'Username' %}
</th>
<th
class=
"text-center"
>
{% trans 'Type' %}
</th>
<th
class=
"text-center"
>
{% trans 'UA' %}
</th>
<th
class=
"text-center"
>
{% trans 'IP' %}
</th>
<th
class=
"text-center"
>
{% trans 'City' %}
</th>
<th
class=
"text-center"
>
{% trans 'Date' %}
</th>
{% endblock %}
{% block table_body %}
{% for login_log in object_list %}
<tr
class=
"gradeX"
>
<td
class=
"text-center"
>
{{ forloop.counter }}
</td>
<td
class=
"text-center"
>
{{ login_log.username }}
</td>
<td
class=
"text-center"
>
{{ login_log.get_type_display }}
</td>
<td
class=
"text-center"
>
<span
href=
"javascript:void(0);"
data-toggle=
"tooltips"
title=
"{{ login_log.user_agent }}"
>
{{ login_log.user_agent | truncatechars:20 }}
</span>
</td>
<td
class=
"text-center"
>
{{ login_log.ip }}
</td>
<td
class=
"text-center"
>
{{ login_log.city }}
</td>
<td
class=
"text-center"
>
{{ login_log.datetime }}
</td>
</tr>
{% endfor %}
{% endblock %}
{% block custom_foot_js %}
<script
src=
"{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"
></script>
<script>
$
(
document
).
ready
(
function
()
{
$
(
'
table
'
).
DataTable
({
"
searching
"
:
false
,
"
bInfo
"
:
false
,
"
paging
"
:
false
,
"
order
"
:
[]
});
$
(
'
#date .input-daterange
'
).
datepicker
({
dateFormat
:
'
mm/dd/yy
'
,
keyboardNavigation
:
false
,
forceParse
:
false
,
autoclose
:
true
});
$
(
'
.select2
'
).
select2
();
})
</script>
{% endblock %}
apps/users/urls/views_urls.py
浏览文件 @
ec8106e4
...
@@ -43,4 +43,7 @@ urlpatterns = [
...
@@ -43,4 +43,7 @@ urlpatterns = [
url
(
r
'^user-group/(?P<pk>[0-9a-zA-Z\-]+)/asset-permission$'
,
views
.
UserGroupAssetPermissionView
.
as_view
(),
name
=
'user-group-asset-permission'
),
url
(
r
'^user-group/(?P<pk>[0-9a-zA-Z\-]+)/asset-permission$'
,
views
.
UserGroupAssetPermissionView
.
as_view
(),
name
=
'user-group-asset-permission'
),
url
(
r
'^user-group/(?P<pk>[0-9a-zA-Z\-]+)/asset-permission/create$'
,
views
.
UserGroupAssetPermissionCreateView
.
as_view
(),
name
=
'user-group-asset-permission-create'
),
url
(
r
'^user-group/(?P<pk>[0-9a-zA-Z\-]+)/asset-permission/create$'
,
views
.
UserGroupAssetPermissionCreateView
.
as_view
(),
name
=
'user-group-asset-permission-create'
),
url
(
r
'^user-group/(?P<pk>[0-9a-zA-Z\-]+)/assets'
,
views
.
UserGroupGrantedAssetView
.
as_view
(),
name
=
'user-group-granted-asset'
),
url
(
r
'^user-group/(?P<pk>[0-9a-zA-Z\-]+)/assets'
,
views
.
UserGroupGrantedAssetView
.
as_view
(),
name
=
'user-group-granted-asset'
),
# Login log
url
(
r
'^login-log/$'
,
views
.
LoginLogListView
.
as_view
(),
name
=
'login-log-list'
),
]
]
apps/users/utils.py
浏览文件 @
ec8106e4
...
@@ -9,7 +9,7 @@ import requests
...
@@ -9,7 +9,7 @@ import requests
import
ipaddress
import
ipaddress
from
django.conf
import
settings
from
django.conf
import
settings
from
django.contrib.auth.mixins
import
UserPassesTestMixin
from
django.contrib.auth.mixins
import
UserPassesTestMixin
from
django.contrib.auth
import
authenticate
from
django.contrib.auth
import
authenticate
,
login
as
auth_login
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
django.core.cache
import
cache
from
django.core.cache
import
cache
...
...
apps/users/views/login.py
浏览文件 @
ec8106e4
...
@@ -5,7 +5,9 @@ from django import forms
...
@@ -5,7 +5,9 @@ from django import forms
from
django.shortcuts
import
render
from
django.shortcuts
import
render
from
django.contrib.auth
import
login
as
auth_login
,
logout
as
auth_logout
from
django.contrib.auth
import
login
as
auth_login
,
logout
as
auth_logout
from
django.contrib.auth.mixins
import
LoginRequiredMixin
from
django.contrib.auth.mixins
import
LoginRequiredMixin
from
django.views.generic
import
ListView
from
django.core.files.storage
import
default_storage
from
django.core.files.storage
import
default_storage
from
django.db.models
import
Q
from
django.http
import
HttpResponseRedirect
from
django.http
import
HttpResponseRedirect
from
django.shortcuts
import
reverse
,
redirect
from
django.shortcuts
import
reverse
,
redirect
from
django.utils.decorators
import
method_decorator
from
django.utils.decorators
import
method_decorator
...
@@ -17,9 +19,10 @@ from django.views.generic.base import TemplateView
...
@@ -17,9 +19,10 @@ from django.views.generic.base import TemplateView
from
django.views.generic.edit
import
FormView
from
django.views.generic.edit
import
FormView
from
formtools.wizard.views
import
SessionWizardView
from
formtools.wizard.views
import
SessionWizardView
from
django.conf
import
settings
from
django.conf
import
settings
from
django.utils
import
timezone
from
common.utils
import
get_object_or_none
from
common.utils
import
get_object_or_none
from
..models
import
User
from
..models
import
User
,
LoginLog
from
..utils
import
send_reset_password_mail
from
..utils
import
send_reset_password_mail
from
..tasks
import
write_login_log_async
from
..tasks
import
write_login_log_async
from
..
import
forms
from
..
import
forms
...
@@ -28,7 +31,7 @@ from .. import forms
...
@@ -28,7 +31,7 @@ from .. import forms
__all__
=
[
'UserLoginView'
,
'UserLogoutView'
,
__all__
=
[
'UserLoginView'
,
'UserLogoutView'
,
'UserForgotPasswordView'
,
'UserForgotPasswordSendmailSuccessView'
,
'UserForgotPasswordView'
,
'UserForgotPasswordSendmailSuccessView'
,
'UserResetPasswordView'
,
'UserResetPasswordSuccessView'
,
'UserResetPasswordView'
,
'UserResetPasswordSuccessView'
,
'UserFirstLoginView'
]
'UserFirstLoginView'
,
'LoginLogListView'
]
@
method_decorator
(
sensitive_post_parameters
(),
name
=
'dispatch'
)
@
method_decorator
(
sensitive_post_parameters
(),
name
=
'dispatch'
)
...
@@ -48,10 +51,10 @@ class UserLoginView(FormView):
...
@@ -48,10 +51,10 @@ class UserLoginView(FormView):
auth_login
(
self
.
request
,
form
.
get_user
())
auth_login
(
self
.
request
,
form
.
get_user
())
login_ip
=
self
.
request
.
META
.
get
(
'REMOTE_ADDR'
,
''
)
login_ip
=
self
.
request
.
META
.
get
(
'REMOTE_ADDR'
,
''
)
user_agent
=
self
.
request
.
META
.
get
(
'HTTP_USER_AGENT'
,
''
)
user_agent
=
self
.
request
.
META
.
get
(
'HTTP_USER_AGENT'
,
''
)
write_login_log_async
.
delay
(
self
.
request
.
user
.
username
,
write_login_log_async
.
delay
(
self
.
request
.
user
.
name
,
self
.
request
.
user
.
username
,
type
=
'W'
,
login_type
=
'W'
,
login_ip
=
login_ip
,
ip
=
login_ip
,
user_agent
=
user_agent
user_agent
=
user_agent
)
)
return
redirect
(
self
.
get_success_url
())
return
redirect
(
self
.
get_success_url
())
def
get_success_url
(
self
):
def
get_success_url
(
self
):
...
@@ -202,3 +205,60 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
...
@@ -202,3 +205,60 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
form
.
instance
=
self
.
request
.
user
form
.
instance
=
self
.
request
.
user
return
form
return
form
class
LoginLogListView
(
ListView
):
template_name
=
'users/login_log_list.html'
model
=
LoginLog
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
username
=
keyword
=
date_from_s
=
date_to_s
=
""
date_format
=
'%m/%d/%Y'
def
get_queryset
(
self
):
date_to_default
=
timezone
.
now
()
date_from_default
=
timezone
.
now
()
-
timezone
.
timedelta
(
7
)
date_to_default_s
=
date_to_default
.
strftime
(
self
.
date_format
)
date_from_default_s
=
date_from_default
.
strftime
(
self
.
date_format
)
self
.
username
=
self
.
request
.
GET
.
get
(
'username'
,
''
)
self
.
keyword
=
self
.
request
.
GET
.
get
(
"keyword"
,
''
)
self
.
date_from_s
=
self
.
request
.
GET
.
get
(
'date_from'
,
date_from_default_s
)
self
.
date_to_s
=
self
.
request
.
GET
.
get
(
'date_to'
,
date_to_default_s
)
self
.
queryset
=
super
().
get_queryset
()
if
self
.
username
:
self
.
queryset
=
self
.
queryset
.
filter
(
username
=
self
.
username
)
if
self
.
date_from_s
:
date_from
=
timezone
.
datetime
.
strptime
(
self
.
date_from_s
,
'%m/%d/%Y'
)
date_from
=
date_from
.
replace
(
tzinfo
=
timezone
.
get_current_timezone
()
)
self
.
queryset
=
self
.
queryset
.
filter
(
datetime__gt
=
date_from
)
if
self
.
date_to_s
:
date_to
=
timezone
.
datetime
.
strptime
(
self
.
date_to_s
+
' 23:59:59'
,
'%m/%d/%Y %H:%M:%S'
)
date_to
=
date_to
.
replace
(
tzinfo
=
timezone
.
get_current_timezone
()
)
self
.
queryset
=
self
.
queryset
.
filter
(
datetime__lt
=
date_to
)
if
self
.
keyword
:
self
.
queryset
=
self
.
queryset
.
filter
(
Q
(
ip__contains
=
self
.
keyword
)
|
Q
(
city__contains
=
self
.
keyword
)
|
Q
(
username__contains
=
self
.
keyword
)
)
return
self
.
queryset
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
_
(
'Users'
),
'action'
:
_
(
'Login log list'
),
'date_from'
:
self
.
date_from_s
,
'date_to'
:
self
.
date_to_s
,
'username'
:
self
.
username
,
'keyword'
:
self
.
keyword
,
'user_list'
:
set
(
LoginLog
.
objects
.
all
().
values_list
(
'username'
,
flat
=
True
))
}
kwargs
.
update
(
context
)
return
super
().
get_context_data
(
**
kwargs
)
\ No newline at end of file
requirements/requirements.txt
浏览文件 @
ec8106e4
Django
>
=1.11
Django
=
=1.11
django-bootstrap3>=8.2.2
django-bootstrap3>=8.2.2
Pillow>=4.1.0
Pillow>=4.1.0
djangorestframework>=3.6.2
djangorestframework>=3.6.2
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录