Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
ec8106e4
Commit
ec8106e4
authored
Dec 05, 2017
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Feature] 完成登陆日志
parent
a5f97359
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
169 additions
and
17 deletions
+169
-17
views.py
apps/jumpserver/views.py
+0
-1
_nav.html
apps/templates/_nav.html
+1
-1
api.py
apps/users/api.py
+2
-3
authentication.py
apps/users/models/authentication.py
+2
-4
login_log_list.html
apps/users/templates/users/login_log_list.html
+92
-0
views_urls.py
apps/users/urls/views_urls.py
+3
-0
utils.py
apps/users/utils.py
+1
-1
login.py
apps/users/views/login.py
+67
-6
requirements.txt
requirements/requirements.txt
+1
-1
No files found.
apps/jumpserver/views.py
View file @
ec8106e4
...
...
@@ -94,7 +94,6 @@ class IndexView(LoginRequiredMixin, TemplateView):
for
asset
in
assets
:
last_login
=
self
.
session_week
.
filter
(
asset
=
asset
[
"asset"
])
.
order_by
(
'date_start'
)
.
last
()
asset
[
'last'
]
=
last_login
print
(
asset
)
return
assets
def
get_week_top10_user
(
self
):
...
...
apps/templates/_nav.html
View file @
ec8106e4
...
...
@@ -11,7 +11,7 @@
<ul
class=
"nav nav-second-level active"
>
<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 'Login logs' %}
</a></li>
<li
id=
"
login-log"
><a
href=
"{% url 'users:login-log
-list' %}"
>
{% trans 'Login logs' %}
</a></li>
</ul>
</li>
<li
id=
"assets"
>
...
...
apps/users/api.py
View file @
ec8106e4
...
...
@@ -164,9 +164,8 @@ class UserAuthApi(APIView):
if
user
:
token
=
generate_token
(
request
,
user
)
write_login_log_async
.
delay
(
user
.
username
,
name
=
user
.
name
,
user_agent
=
user_agent
,
login_ip
=
login_ip
,
login_type
=
login_type
user
.
username
,
ip
=
login_ip
,
type
=
login_type
,
user_agent
=
user_agent
,
)
return
Response
({
'token'
:
token
,
'user'
:
user
.
to_json
()})
else
:
...
...
apps/users/models/authentication.py
View file @
ec8106e4
...
...
@@ -16,8 +16,7 @@ class AccessKey(models.Model):
default
=
uuid
.
uuid4
,
editable
=
False
)
secret
=
models
.
UUIDField
(
verbose_name
=
'AccessKeySecret'
,
default
=
uuid
.
uuid4
,
editable
=
False
)
user
=
models
.
ForeignKey
(
User
,
verbose_name
=
'User'
,
related_name
=
'access_key'
)
user
=
models
.
ForeignKey
(
User
,
verbose_name
=
'User'
,
on_delete
=
models
.
CASCADE
,
related_name
=
'access_key'
)
def
get_id
(
self
):
return
str
(
self
.
id
)
...
...
@@ -39,8 +38,7 @@ class PrivateToken(Token):
class
LoginLog
(
models
.
Model
):
LOGIN_TYPE_CHOICE
=
(
(
'W'
,
'Web'
),
(
'ST'
,
'SSH Terminal'
),
(
'WT'
,
'Web Terminal'
)
(
'T'
,
'Terminal'
),
)
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
username
=
models
.
CharField
(
max_length
=
20
,
verbose_name
=
_
(
'Username'
))
...
...
apps/users/templates/users/login_log_list.html
0 → 100644
View file @
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
View file @
ec8106e4
...
...
@@ -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/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'
),
# Login log
url
(
r'^login-log/$'
,
views
.
LoginLogListView
.
as_view
(),
name
=
'login-log-list'
),
]
apps/users/utils.py
View file @
ec8106e4
...
...
@@ -9,7 +9,7 @@ import requests
import
ipaddress
from
django.conf
import
settings
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.core.cache
import
cache
...
...
apps/users/views/login.py
View file @
ec8106e4
...
...
@@ -5,7 +5,9 @@ from django import forms
from
django.shortcuts
import
render
from
django.contrib.auth
import
login
as
auth_login
,
logout
as
auth_logout
from
django.contrib.auth.mixins
import
LoginRequiredMixin
from
django.views.generic
import
ListView
from
django.core.files.storage
import
default_storage
from
django.db.models
import
Q
from
django.http
import
HttpResponseRedirect
from
django.shortcuts
import
reverse
,
redirect
from
django.utils.decorators
import
method_decorator
...
...
@@ -17,9 +19,10 @@ from django.views.generic.base import TemplateView
from
django.views.generic.edit
import
FormView
from
formtools.wizard.views
import
SessionWizardView
from
django.conf
import
settings
from
django.utils
import
timezone
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
..tasks
import
write_login_log_async
from
..
import
forms
...
...
@@ -28,7 +31,7 @@ from .. import forms
__all__
=
[
'UserLoginView'
,
'UserLogoutView'
,
'UserForgotPasswordView'
,
'UserForgotPasswordSendmailSuccessView'
,
'UserResetPasswordView'
,
'UserResetPasswordSuccessView'
,
'UserFirstLoginView'
]
'UserFirstLoginView'
,
'LoginLogListView'
]
@method_decorator
(
sensitive_post_parameters
(),
name
=
'dispatch'
)
...
...
@@ -48,10 +51,10 @@ class UserLoginView(FormView):
auth_login
(
self
.
request
,
form
.
get_user
())
login_ip
=
self
.
request
.
META
.
get
(
'REMOTE_ADDR'
,
''
)
user_agent
=
self
.
request
.
META
.
get
(
'HTTP_USER_AGENT'
,
''
)
write_login_log_async
.
delay
(
self
.
request
.
user
.
username
,
self
.
request
.
user
.
name
,
login_type
=
'W'
,
login_ip
=
login_ip
,
user_agent
=
user_agent
)
write_login_log_async
.
delay
(
self
.
request
.
user
.
username
,
type
=
'W'
,
ip
=
login_ip
,
user_agent
=
user_agent
)
return
redirect
(
self
.
get_success_url
())
def
get_success_url
(
self
):
...
...
@@ -202,3 +205,60 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
form
.
instance
=
self
.
request
.
user
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
View file @
ec8106e4
Django
>
=1.11
Django
=
=1.11
django-bootstrap3>=8.2.2
Pillow>=4.1.0
djangorestframework>=3.6.2
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment