mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-09-15 23:08:20 +00:00
feat: 用户异地登陆
This commit is contained in:
75
apps/authentication/notifications.py
Normal file
75
apps/authentication/notifications.py
Normal file
@@ -0,0 +1,75 @@
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from notifications.notifications import UserMessage
|
||||
from settings.api import PublicSettingApi
|
||||
from common.utils import get_logger
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
EMAIL_TEMPLATE = _(
|
||||
""
|
||||
"<h3>{subject}</h3>"
|
||||
"<p>Dear {server_name} user, Hello!</p>"
|
||||
"<p>Your account has remote login behavior, please pay attention.</p>"
|
||||
"<p>User: {username}</p>"
|
||||
"<p>Login time: {time}</p>"
|
||||
"<p>Login location: {city} ({ip})</p>"
|
||||
"<p>If you suspect that the login behavior is abnormal, please modify "
|
||||
"<p>the account password in time.</p>"
|
||||
"<br>"
|
||||
"<p>Thank you for your attention to {server_name}!</p>")
|
||||
|
||||
|
||||
class DifferentCityLoginMessage(UserMessage):
|
||||
def __init__(self, user, ip, city):
|
||||
self.ip = ip
|
||||
self.city = city
|
||||
super().__init__(user)
|
||||
|
||||
@property
|
||||
def time(self):
|
||||
return timezone.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
@property
|
||||
def subject(self):
|
||||
return _('Different city login reminder')
|
||||
|
||||
def get_text_msg(self) -> dict:
|
||||
message = _(
|
||||
""
|
||||
"{subject}\n"
|
||||
"Dear {server_name} user, Hello!\n"
|
||||
"Your account has remote login behavior, please pay attention.\n"
|
||||
"User: {username}\n"
|
||||
"Login time: {time}\n"
|
||||
"Login location: {city} ({ip})\n"
|
||||
"If you suspect that the login behavior is abnormal, please modify "
|
||||
"the account password in time.\n"
|
||||
"Thank you for your attention to {server_name}!\n"
|
||||
).format(
|
||||
subject=self.subject,
|
||||
server_name=PublicSettingApi.get_login_title(),
|
||||
username=self.user.username,
|
||||
ip=self.ip,
|
||||
time=self.time,
|
||||
city=self.city,
|
||||
)
|
||||
return {
|
||||
'subject': self.subject,
|
||||
'message': message
|
||||
}
|
||||
|
||||
def get_html_msg(self) -> dict:
|
||||
message = EMAIL_TEMPLATE.format(
|
||||
subject=self.subject,
|
||||
server_name=PublicSettingApi.get_login_title(),
|
||||
username=self.user.username,
|
||||
ip=self.ip,
|
||||
time=self.time,
|
||||
city=self.city,
|
||||
)
|
||||
return {
|
||||
'subject': self.subject,
|
||||
'message': message
|
||||
}
|
@@ -4,6 +4,12 @@ import base64
|
||||
from Cryptodome.PublicKey import RSA
|
||||
from Cryptodome.Cipher import PKCS1_v1_5
|
||||
from Cryptodome import Random
|
||||
|
||||
from .notifications import DifferentCityLoginMessage
|
||||
from audits.models import UserLoginLog
|
||||
from audits.const import DEFAULT_CITY
|
||||
from common.utils import get_request_ip
|
||||
from common.utils import validate_ip, get_ip_city
|
||||
from common.utils import get_logger
|
||||
|
||||
logger = get_logger(__file__)
|
||||
@@ -43,3 +49,16 @@ def rsa_decrypt(cipher_text, rsa_private_key=None):
|
||||
cipher_decoded = base64.b16decode(hex_fixed.upper())
|
||||
message = cipher.decrypt(cipher_decoded, b'error').decode()
|
||||
return message
|
||||
|
||||
|
||||
def check_different_city_login(user, request):
|
||||
ip = get_request_ip(request) or '0.0.0.0'
|
||||
|
||||
if not (ip and validate_ip(ip)):
|
||||
city = DEFAULT_CITY
|
||||
else:
|
||||
city = get_ip_city(ip) or DEFAULT_CITY
|
||||
|
||||
last_user_login = UserLoginLog.objects.filter(username=user.username, status=True).first()
|
||||
if last_user_login.city != city:
|
||||
DifferentCityLoginMessage(user, ip, city).publish_async()
|
||||
|
Reference in New Issue
Block a user