mirror of https://github.com/jumpserver/jumpserver
perf: 优化登录,cas, openid 自动登录
parent
7294f6e5e0
commit
4d6d4cbc22
|
@ -7,13 +7,14 @@ import time
|
|||
|
||||
from django.conf import settings
|
||||
from django.contrib import auth
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.contrib.auth import (
|
||||
BACKEND_SESSION_KEY, _get_backends,
|
||||
PermissionDenied, user_login_failed, _clean_credentials
|
||||
)
|
||||
from django.shortcuts import reverse
|
||||
|
||||
from common.utils import get_object_or_none, get_request_ip, get_logger, bulk_get
|
||||
from common.utils import get_object_or_none, get_request_ip, get_logger, bulk_get, FlashMessageUtil
|
||||
from users.models import User
|
||||
from users.utils import LoginBlockUtil, MFABlockUtils
|
||||
from . import errors
|
||||
|
@ -204,41 +205,40 @@ class AuthMixin:
|
|||
return user
|
||||
|
||||
@classmethod
|
||||
def generate_reset_password_url_with_flash_msg(cls, user: User, flash_view_name):
|
||||
def generate_reset_password_url_with_flash_msg(cls, user, message):
|
||||
reset_passwd_url = reverse('authentication:reset-password')
|
||||
query_str = urlencode({
|
||||
'token': user.generate_reset_token()
|
||||
})
|
||||
reset_passwd_url = f'{reset_passwd_url}?{query_str}'
|
||||
|
||||
flash_page_url = reverse(flash_view_name)
|
||||
query_str = urlencode({
|
||||
'redirect_url': reset_passwd_url
|
||||
})
|
||||
return f'{flash_page_url}?{query_str}'
|
||||
message_data = {
|
||||
'title': _('Please change your password'),
|
||||
'message': message,
|
||||
'interval': 3,
|
||||
'redirect_url': reset_passwd_url,
|
||||
}
|
||||
return FlashMessageUtil.gen_message_url(message_data)
|
||||
|
||||
@classmethod
|
||||
def _check_passwd_is_too_simple(cls, user: User, password):
|
||||
if user.is_superuser and password == 'admin':
|
||||
url = cls.generate_reset_password_url_with_flash_msg(
|
||||
user, 'authentication:passwd-too-simple-flash-msg'
|
||||
)
|
||||
message = _('Your password is too simple, please change it for security')
|
||||
url = cls.generate_reset_password_url_with_flash_msg(user, message=message)
|
||||
raise errors.PasswdTooSimple(url)
|
||||
|
||||
@classmethod
|
||||
def _check_passwd_need_update(cls, user: User):
|
||||
if user.need_update_password:
|
||||
url = cls.generate_reset_password_url_with_flash_msg(
|
||||
user, 'authentication:passwd-need-update-flash-msg'
|
||||
)
|
||||
message = _('You should to change your password before login')
|
||||
url = cls.generate_reset_password_url_with_flash_msg(user, message)
|
||||
raise errors.PasswdNeedUpdate(url)
|
||||
|
||||
@classmethod
|
||||
def _check_password_require_reset_or_not(cls, user: User):
|
||||
if user.password_has_expired:
|
||||
url = cls.generate_reset_password_url_with_flash_msg(
|
||||
user, 'authentication:passwd-has-expired-flash-msg'
|
||||
)
|
||||
message = _('Your password has expired, please reset before logging in')
|
||||
url = cls.generate_reset_password_url_with_flash_msg(user, message)
|
||||
raise errors.PasswordRequireResetError(url)
|
||||
|
||||
def check_user_auth_if_need(self, decrypt_passwd=False):
|
||||
|
|
|
@ -18,13 +18,7 @@ urlpatterns = [
|
|||
|
||||
# 原来在users中的
|
||||
path('password/forgot/', users_view.UserForgotPasswordView.as_view(), name='forgot-password'),
|
||||
path('password/forgot/sendmail-success/', users_view.UserForgotPasswordSendmailSuccessView.as_view(),
|
||||
name='forgot-password-sendmail-success'),
|
||||
path('password/reset/', users_view.UserResetPasswordView.as_view(), name='reset-password'),
|
||||
path('password/too-simple-flash-msg/', views.FlashPasswdTooSimpleMsgView.as_view(), name='passwd-too-simple-flash-msg'),
|
||||
path('password/need-update-flash-msg/', views.FlashPasswdNeedUpdateMsgView.as_view(), name='passwd-need-update-flash-msg'),
|
||||
path('password/has-expired-msg/', views.FlashPasswdHasExpiredMsgView.as_view(), name='passwd-has-expired-flash-msg'),
|
||||
path('password/reset/success/', users_view.UserResetPasswordSuccessView.as_view(), name='reset-password-success'),
|
||||
path('password/verify/', users_view.UserVerifyPasswordView.as_view(), name='user-verify-password'),
|
||||
|
||||
# Profile
|
||||
|
|
|
@ -19,7 +19,7 @@ from django.conf import settings
|
|||
from django.urls import reverse_lazy
|
||||
from django.contrib.auth import BACKEND_SESSION_KEY
|
||||
|
||||
from common.utils import get_request_ip, get_object_or_none
|
||||
from common.utils import get_request_ip, FlashMessageUtil
|
||||
from users.utils import (
|
||||
redirect_user_first_login_or_index
|
||||
)
|
||||
|
@ -31,8 +31,6 @@ from ..forms import get_user_login_form_cls
|
|||
__all__ = [
|
||||
'UserLoginView', 'UserLogoutView',
|
||||
'UserLoginGuardView', 'UserLoginWaitConfirmView',
|
||||
'FlashPasswdTooSimpleMsgView', 'FlashPasswdHasExpiredMsgView',
|
||||
'FlashPasswdNeedUpdateMsgView'
|
||||
]
|
||||
|
||||
|
||||
|
@ -44,12 +42,42 @@ class UserLoginView(mixins.AuthMixin, FormView):
|
|||
redirect_field_name = 'next'
|
||||
template_name = 'authentication/login.html'
|
||||
|
||||
def redirect_third_party_auth_if_need(self, request):
|
||||
# show jumpserver login page if request http://{JUMP-SERVER}/?admin=1
|
||||
if self.request.GET.get("admin", 0):
|
||||
return None
|
||||
auth_type = ''
|
||||
auth_url = ''
|
||||
if settings.AUTH_OPENID:
|
||||
auth_type = 'OIDC'
|
||||
auth_url = reverse(settings.AUTH_OPENID_AUTH_LOGIN_URL_NAME)
|
||||
elif settings.AUTH_CAS:
|
||||
auth_type = 'CAS'
|
||||
auth_url = reverse(settings.CAS_LOGIN_URL_NAME)
|
||||
if not auth_url:
|
||||
return None
|
||||
|
||||
message_data = {
|
||||
'title': _('Redirecting'),
|
||||
'message': _("Redirecting to {} authentication").format(auth_type),
|
||||
'redirect_url': auth_url,
|
||||
'has_cancel': True,
|
||||
'cancel_url': reverse('authentication:login') + '?admin=1'
|
||||
}
|
||||
redirect_url = FlashMessageUtil.gen_message_url(message_data)
|
||||
query_string = request.GET.urlencode()
|
||||
redirect_url = "{}&{}".format(redirect_url, query_string)
|
||||
return redirect_url
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if request.user.is_staff:
|
||||
first_login_url = redirect_user_first_login_or_index(
|
||||
request, self.redirect_field_name
|
||||
)
|
||||
return redirect(first_login_url)
|
||||
redirect_url = self.redirect_third_party_auth_if_need(request)
|
||||
if redirect_url:
|
||||
return redirect(redirect_url)
|
||||
request.session.set_test_cookie()
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
|
@ -225,50 +253,3 @@ class UserLogoutView(TemplateView):
|
|||
}
|
||||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
@method_decorator(never_cache, name='dispatch')
|
||||
class FlashPasswdTooSimpleMsgView(TemplateView):
|
||||
template_name = 'flash_message_standalone.html'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
context = {
|
||||
'title': _('Please change your password'),
|
||||
'messages': _('Your password is too simple, please change it for security'),
|
||||
'interval': 3,
|
||||
'redirect_url': request.GET.get('redirect_url'),
|
||||
'auto_redirect': True,
|
||||
}
|
||||
return self.render_to_response(context)
|
||||
|
||||
|
||||
@method_decorator(never_cache, name='dispatch')
|
||||
class FlashPasswdNeedUpdateMsgView(TemplateView):
|
||||
template_name = 'flash_message_standalone.html'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
context = {
|
||||
'title': _('Please change your password'),
|
||||
'messages': _('You should to change your password before login'),
|
||||
'interval': 3,
|
||||
'redirect_url': request.GET.get('redirect_url'),
|
||||
'auto_redirect': True,
|
||||
'confirm_button': _('Confirm')
|
||||
}
|
||||
return self.render_to_response(context)
|
||||
|
||||
|
||||
@method_decorator(never_cache, name='dispatch')
|
||||
class FlashPasswdHasExpiredMsgView(TemplateView):
|
||||
template_name = 'flash_message_standalone.html'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
context = {
|
||||
'title': _('Please change your password'),
|
||||
'messages': _('Your password has expired, please reset before logging in'),
|
||||
'interval': 3,
|
||||
'redirect_url': request.GET.get('redirect_url'),
|
||||
'auto_redirect': True,
|
||||
'confirm_button': _('Confirm')
|
||||
}
|
||||
return self.render_to_response(context)
|
||||
|
|
|
@ -5,7 +5,7 @@ from django.contrib.auth.mixins import UserPassesTestMixin
|
|||
from django.utils import timezone
|
||||
|
||||
|
||||
__all__ = ["DatetimeSearchMixin"]
|
||||
__all__ = ["DatetimeSearchMixin", "PermissionsMixin"]
|
||||
|
||||
from rest_framework import permissions
|
||||
|
||||
|
@ -51,4 +51,4 @@ class PermissionsMixin(UserPassesTestMixin):
|
|||
for permission_class in permission_classes:
|
||||
if not permission_class().has_permission(self.request, self):
|
||||
return False
|
||||
return True
|
||||
return True
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
from django.urls import path
|
||||
|
||||
from .. import views
|
||||
|
||||
app_name = 'common'
|
||||
|
||||
urlpatterns = [
|
||||
# login
|
||||
path('flash-message/', views.FlashMessageMsgView.as_view(), name='flash-message'),
|
||||
]
|
|
@ -8,3 +8,4 @@ from .http import *
|
|||
from .ipip import *
|
||||
from .crypto import *
|
||||
from .random import *
|
||||
from .jumpserver import *
|
|
@ -0,0 +1,31 @@
|
|||
from django.core.cache import cache
|
||||
from django.shortcuts import reverse
|
||||
|
||||
from .random import random_string
|
||||
|
||||
|
||||
__all__ = ['FlashMessageUtil']
|
||||
|
||||
|
||||
class FlashMessageUtil:
|
||||
@staticmethod
|
||||
def get_key(code):
|
||||
key = 'MESSAGE_{}'.format(code)
|
||||
return key
|
||||
|
||||
@classmethod
|
||||
def get_message_code(cls, message_data):
|
||||
code = random_string(12)
|
||||
key = cls.get_key(code)
|
||||
cache.set(key, message_data, 60)
|
||||
return code
|
||||
|
||||
@classmethod
|
||||
def get_message_by_code(cls, code):
|
||||
key = cls.get_key(code)
|
||||
return cache.get(key)
|
||||
|
||||
@classmethod
|
||||
def gen_message_url(cls, message_data):
|
||||
code = cls.get_message_code(message_data)
|
||||
return reverse('common:flash-message') + f'?code={code}'
|
|
@ -0,0 +1,40 @@
|
|||
#
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.cache import never_cache
|
||||
from django.http import HttpResponse
|
||||
from django.views.generic.base import TemplateView
|
||||
|
||||
from common.utils import bulk_get, FlashMessageUtil
|
||||
|
||||
|
||||
@method_decorator(never_cache, name='dispatch')
|
||||
class FlashMessageMsgView(TemplateView):
|
||||
template_name = 'flash_message_standalone.html'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
code = request.GET.get('code')
|
||||
if not code:
|
||||
return HttpResponse('Not found the code')
|
||||
|
||||
message_data = FlashMessageUtil.get_message_by_code(code)
|
||||
if not message_data:
|
||||
return HttpResponse('Message code error')
|
||||
|
||||
title, message, redirect_url, confirm_button, cancel_url = bulk_get(
|
||||
message_data, 'title', 'message', 'redirect_url', 'confirm_button', 'cancel_url'
|
||||
)
|
||||
|
||||
interval = message_data.get('interval', 3)
|
||||
auto_redirect = message_data.get('auto_redirect', True)
|
||||
has_cancel = message_data.get('has_cancel', False)
|
||||
context = {
|
||||
'title': title,
|
||||
'messages': message,
|
||||
'interval': interval,
|
||||
'redirect_url': redirect_url,
|
||||
'auto_redirect': auto_redirect,
|
||||
'confirm_button': confirm_button,
|
||||
'has_cancel': has_cancel,
|
||||
'cancel_url': cancel_url,
|
||||
}
|
||||
return self.render_to_response(context)
|
|
@ -29,6 +29,7 @@ api_v1 = [
|
|||
app_view_patterns = [
|
||||
path('auth/', include('authentication.urls.view_urls'), name='auth'),
|
||||
path('ops/', include('ops.urls.view_urls'), name='ops'),
|
||||
path('common/', include('common.urls.view_urls'), name='common'),
|
||||
re_path(r'flower/(?P<path>.*)', views.celery_flower_view, name='flower-view'),
|
||||
]
|
||||
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
import re
|
||||
import time
|
||||
|
||||
from django.http import HttpResponseRedirect, JsonResponse, Http404
|
||||
from django.conf import settings
|
||||
from django.views.generic import View
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.permissions import AllowAny
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.http import HttpResponse
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from common.http import HttpResponseTemporaryRedirect
|
||||
|
||||
|
@ -85,3 +83,4 @@ class KokoView(View):
|
|||
"<div>Koko is a separately deployed program, you need to deploy Koko, configure nginx for url distribution,</div> "
|
||||
"</div>If you see this page, prove that you are not accessing the nginx listening port. Good luck.</div>")
|
||||
return HttpResponse(msg)
|
||||
|
||||
|
|
Binary file not shown.
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: JumpServer 0.3.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-04-29 12:17+0800\n"
|
||||
"POT-Creation-Date: 2021-04-29 16:20+0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
||||
|
@ -354,7 +354,9 @@ msgid "You can't delete the root node ({})"
|
|||
msgstr "不能删除根节点 ({})"
|
||||
|
||||
#: assets/api/node.py:75
|
||||
msgid "Deletion failed and the node contains children or assets"
|
||||
#, fuzzy
|
||||
#| msgid "Deletion failed and the node contains children or assets"
|
||||
msgid "Deletion failed and the node contains assets"
|
||||
msgstr "删除失败,节点包含子节点或资产"
|
||||
|
||||
#: assets/backends/db.py:244
|
||||
|
@ -650,31 +652,31 @@ msgstr "资产组"
|
|||
msgid "Default asset group"
|
||||
msgstr "默认资产组"
|
||||
|
||||
#: assets/models/label.py:19 assets/models/node.py:547 settings/models.py:30
|
||||
#: assets/models/label.py:19 assets/models/node.py:546 settings/models.py:30
|
||||
msgid "Value"
|
||||
msgstr "值"
|
||||
|
||||
#: assets/models/node.py:152
|
||||
#: assets/models/node.py:151
|
||||
msgid "New node"
|
||||
msgstr "新节点"
|
||||
|
||||
#: assets/models/node.py:475 users/templates/users/_granted_assets.html:130
|
||||
#: assets/models/node.py:474 users/templates/users/_granted_assets.html:130
|
||||
msgid "empty"
|
||||
msgstr "空"
|
||||
|
||||
#: assets/models/node.py:546 perms/models/asset_permission.py:176
|
||||
#: assets/models/node.py:545 perms/models/asset_permission.py:176
|
||||
msgid "Key"
|
||||
msgstr "键"
|
||||
|
||||
#: assets/models/node.py:548
|
||||
#: assets/models/node.py:547
|
||||
msgid "Full value"
|
||||
msgstr "全称"
|
||||
|
||||
#: assets/models/node.py:551 perms/models/asset_permission.py:177
|
||||
#: assets/models/node.py:550 perms/models/asset_permission.py:177
|
||||
msgid "Parent key"
|
||||
msgstr "ssh私钥"
|
||||
|
||||
#: assets/models/node.py:560 assets/serializers/system_user.py:191
|
||||
#: assets/models/node.py:559 assets/serializers/system_user.py:191
|
||||
#: users/templates/users/user_asset_permission.html:41
|
||||
#: users/templates/users/user_asset_permission.html:73
|
||||
#: users/templates/users/user_asset_permission.html:158
|
||||
|
@ -1360,15 +1362,15 @@ msgstr "来源 IP 不被允许登录"
|
|||
msgid "SSO auth closed"
|
||||
msgstr "SSO 认证关闭了"
|
||||
|
||||
#: authentication/errors.py:271 authentication/views/login.py:237
|
||||
#: authentication/errors.py:271 authentication/views/login.py:267
|
||||
msgid "Your password is too simple, please change it for security"
|
||||
msgstr "你的密码过于简单,为了安全,请修改"
|
||||
|
||||
#: authentication/errors.py:280 authentication/views/login.py:252
|
||||
#: authentication/errors.py:280 authentication/views/login.py:282
|
||||
msgid "You should to change your password before login"
|
||||
msgstr "登录完成前,请先修改密码"
|
||||
|
||||
#: authentication/errors.py:289 authentication/views/login.py:268
|
||||
#: authentication/errors.py:289 authentication/views/login.py:298
|
||||
msgid "Your password has expired, please reset before logging in"
|
||||
msgstr "您的密码已过期,先修改再登录"
|
||||
|
||||
|
@ -1453,8 +1455,9 @@ msgid "Need MFA for view auth"
|
|||
msgstr "需要多因子认证来查看账号信息"
|
||||
|
||||
#: authentication/templates/authentication/_mfa_confirm_modal.html:20
|
||||
#: authentication/views/login.py:256 authentication/views/login.py:272
|
||||
#: templates/_modal.html:23 users/templates/users/user_password_verify.html:20
|
||||
#: authentication/views/login.py:286 authentication/views/login.py:302
|
||||
#: authentication/views/login.py:318 templates/_modal.html:23
|
||||
#: users/templates/users/user_password_verify.html:20
|
||||
msgid "Confirm"
|
||||
msgstr "确认"
|
||||
|
||||
|
@ -1519,7 +1522,6 @@ msgid "Copy link"
|
|||
msgstr "复制链接"
|
||||
|
||||
#: authentication/templates/authentication/login_wait_confirm.html:51
|
||||
#: templates/flash_message_standalone.html:38
|
||||
msgid "Return"
|
||||
msgstr "返回"
|
||||
|
||||
|
@ -1527,11 +1529,19 @@ msgstr "返回"
|
|||
msgid "Copy success"
|
||||
msgstr "复制成功"
|
||||
|
||||
#: authentication/views/login.py:58
|
||||
#: authentication/views/login.py:63 authentication/views/login.py:313
|
||||
msgid "Redirecting"
|
||||
msgstr "跳转中"
|
||||
|
||||
#: authentication/views/login.py:64
|
||||
msgid "Redirecting to {} authentication"
|
||||
msgstr "正在跳转到 {} 认证"
|
||||
|
||||
#: authentication/views/login.py:88
|
||||
msgid "Please enable cookies and try again."
|
||||
msgstr "设置你的浏览器支持cookie"
|
||||
|
||||
#: authentication/views/login.py:183
|
||||
#: authentication/views/login.py:213
|
||||
msgid ""
|
||||
"Wait for <b>{}</b> confirm, You also can copy link to her/him <br/>\n"
|
||||
" Don't close this page"
|
||||
|
@ -1539,23 +1549,27 @@ msgstr ""
|
|||
"等待 <b>{}</b> 确认, 你也可以复制链接发给他/她 <br/>\n"
|
||||
" 不要关闭本页面"
|
||||
|
||||
#: authentication/views/login.py:188
|
||||
#: authentication/views/login.py:218
|
||||
msgid "No ticket found"
|
||||
msgstr "没有发现工单"
|
||||
|
||||
#: authentication/views/login.py:220
|
||||
#: authentication/views/login.py:250
|
||||
msgid "Logout success"
|
||||
msgstr "退出登录成功"
|
||||
|
||||
#: authentication/views/login.py:221
|
||||
#: authentication/views/login.py:251
|
||||
msgid "Logout success, return login page"
|
||||
msgstr "退出登录成功,返回到登录页面"
|
||||
|
||||
#: authentication/views/login.py:236 authentication/views/login.py:251
|
||||
#: authentication/views/login.py:267
|
||||
#: authentication/views/login.py:266 authentication/views/login.py:281
|
||||
#: authentication/views/login.py:297
|
||||
msgid "Please change your password"
|
||||
msgstr "请修改密码"
|
||||
|
||||
#: authentication/views/login.py:314
|
||||
msgid "Redirect to third party auth"
|
||||
msgstr ""
|
||||
|
||||
#: common/const/__init__.py:6
|
||||
#, python-format
|
||||
msgid "%(name)s was created successfully"
|
||||
|
@ -1671,7 +1685,7 @@ msgstr "JumpServer 开源堡垒机"
|
|||
msgid "<h1>Flow service unavailable, check it</h1>"
|
||||
msgstr ""
|
||||
|
||||
#: jumpserver/views/other.py:27
|
||||
#: jumpserver/views/other.py:25
|
||||
msgid ""
|
||||
"<div>Luna is a separately deployed program, you need to deploy Luna, koko, "
|
||||
"configure nginx for url distribution,</div> </div>If you see this page, "
|
||||
|
@ -1680,11 +1694,11 @@ msgstr ""
|
|||
"<div>Luna是单独部署的一个程序,你需要部署luna,koko, </div><div>如果你看到了"
|
||||
"这个页面,证明你访问的不是nginx监听的端口,祝你好运</div>"
|
||||
|
||||
#: jumpserver/views/other.py:71
|
||||
#: jumpserver/views/other.py:69
|
||||
msgid "Websocket server run on port: {}, you should proxy it on nginx"
|
||||
msgstr "Websocket 服务运行在端口: {}, 请检查nginx是否代理是否设置"
|
||||
|
||||
#: jumpserver/views/other.py:85
|
||||
#: jumpserver/views/other.py:83
|
||||
msgid ""
|
||||
"<div>Koko is a separately deployed program, you need to deploy Koko, "
|
||||
"configure nginx for url distribution,</div> </div>If you see this page, "
|
||||
|
@ -2760,6 +2774,14 @@ msgstr "确认删除"
|
|||
msgid "Are you sure delete"
|
||||
msgstr "您确定删除吗?"
|
||||
|
||||
#: templates/flash_message_standalone.html:28
|
||||
msgid "Cancel"
|
||||
msgstr "取消"
|
||||
|
||||
#: templates/flash_message_standalone.html:37
|
||||
msgid "Go"
|
||||
msgstr "跳转"
|
||||
|
||||
#: templates/index.html:11
|
||||
msgid "Total users"
|
||||
msgstr "用户总数"
|
||||
|
@ -4978,9 +5000,6 @@ msgstr "社区版"
|
|||
#~ msgid "This will reset the user password and send a reset mail"
|
||||
#~ msgstr "将失效用户当前密码,并发送重设密码邮件到用户邮箱"
|
||||
|
||||
#~ msgid "Cancel"
|
||||
#~ msgstr "取消"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "The reset-ssh-public-key E-mail has been sent successfully. Please inform "
|
||||
#~ "the user to update his new ssh public key."
|
||||
|
|
|
@ -4,14 +4,6 @@
|
|||
{% block html_title %} {{ title }} {% endblock %}
|
||||
{% block title %} {{ title }}{% endblock %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<style>
|
||||
.passwordBox {
|
||||
max-width: 660px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div>
|
||||
{% if errors %}
|
||||
|
@ -30,12 +22,19 @@
|
|||
</p>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
<div class="col-lg-3">
|
||||
{% if has_cancel %}
|
||||
<div class="col-lg-2">
|
||||
<a href="{{ cancel_url }}" class="btn btn-default block full-width m-b">
|
||||
{% trans 'Cancel' %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col-lg-2">
|
||||
<a href="{{ redirect_url }}" class="btn btn-primary block full-width m-b">
|
||||
{% if confirm_button %}
|
||||
{{ confirm_button }}
|
||||
{% else %}
|
||||
{% trans 'Return' %}
|
||||
{% trans 'Go' %}
|
||||
{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from django.shortcuts import render
|
||||
from django.views.generic import RedirectView
|
||||
from django.core.files.storage import default_storage
|
||||
from django.shortcuts import reverse, redirect
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.views.generic.base import TemplateView
|
||||
from django.conf import settings
|
||||
from django.urls import reverse_lazy
|
||||
from formtools.wizard.views import SessionWizardView
|
||||
from django.views.generic import FormView
|
||||
|
||||
from common.utils import get_object_or_none
|
||||
from common.utils import get_object_or_none, FlashMessageUtil
|
||||
from common.permissions import IsValidUser
|
||||
from common.mixins.views import PermissionsMixin
|
||||
from ...models import User
|
||||
|
@ -24,9 +21,7 @@ from ... import forms
|
|||
|
||||
|
||||
__all__ = [
|
||||
'UserLoginView', 'UserForgotPasswordSendmailSuccessView',
|
||||
'UserResetPasswordSuccessView', 'UserResetPasswordSuccessView',
|
||||
'UserResetPasswordView', 'UserForgotPasswordView', 'UserFirstLoginView',
|
||||
'UserLoginView', 'UserResetPasswordView', 'UserForgotPasswordView', 'UserFirstLoginView',
|
||||
]
|
||||
|
||||
|
||||
|
@ -39,6 +34,17 @@ class UserForgotPasswordView(FormView):
|
|||
template_name = 'users/forgot_password.html'
|
||||
form_class = forms.UserForgotPasswordForm
|
||||
|
||||
@staticmethod
|
||||
def get_redirect_message_url():
|
||||
message_data = {
|
||||
'title': _('Send reset password message'),
|
||||
'message': _('Send reset password mail success, '
|
||||
'login your mail box and follow it '),
|
||||
'redirect_url': reverse('authentication:login'),
|
||||
}
|
||||
url = FlashMessageUtil.gen_message_url(message_data)
|
||||
return url
|
||||
|
||||
def form_valid(self, form):
|
||||
email = form.cleaned_data['email']
|
||||
user = get_object_or_none(User, email=email)
|
||||
|
@ -53,37 +59,9 @@ class UserForgotPasswordView(FormView):
|
|||
).format(user.get_source_display())
|
||||
form.add_error('email', error)
|
||||
return self.form_invalid(form)
|
||||
|
||||
send_reset_password_mail(user)
|
||||
return redirect('authentication:forgot-password-sendmail-success')
|
||||
|
||||
|
||||
class UserForgotPasswordSendmailSuccessView(TemplateView):
|
||||
template_name = 'flash_message_standalone.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'title': _('Send reset password message'),
|
||||
'messages': _('Send reset password mail success, '
|
||||
'login your mail box and follow it '),
|
||||
'redirect_url': reverse('authentication:login'),
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class UserResetPasswordSuccessView(TemplateView):
|
||||
template_name = 'flash_message_standalone.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'title': _('Reset password success'),
|
||||
'messages': _('Reset password success, return to login page'),
|
||||
'redirect_url': reverse('authentication:login'),
|
||||
'auto_redirect': True,
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
||||
url = self.get_redirect_message_url()
|
||||
return redirect(url)
|
||||
|
||||
|
||||
class UserResetPasswordView(FormView):
|
||||
|
@ -139,7 +117,18 @@ class UserResetPasswordView(FormView):
|
|||
user.reset_password(password)
|
||||
User.expired_reset_password_token(token)
|
||||
send_reset_password_success_mail(self.request, user)
|
||||
return redirect('authentication:reset-password-success')
|
||||
url = self.get_redirect_url()
|
||||
return redirect(url)
|
||||
|
||||
@staticmethod
|
||||
def get_redirect_url():
|
||||
message_data = {
|
||||
'title': _('Reset password success'),
|
||||
'message': _('Reset password success, return to login page'),
|
||||
'redirect_url': reverse('authentication:login'),
|
||||
'auto_redirect': True,
|
||||
}
|
||||
return FlashMessageUtil.gen_message_url(message_data)
|
||||
|
||||
|
||||
class UserFirstLoginView(PermissionsMixin, TemplateView):
|
||||
|
|
Loading…
Reference in New Issue