mirror of https://github.com/jumpserver/jumpserver
perf: Client login
parent
3cd68ba0a9
commit
7a9a71197a
|
@ -1,12 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from django.urls import path
|
||||
import django_cas_ng.views
|
||||
from django.urls import path
|
||||
|
||||
from .views import CASLoginView
|
||||
from .views import CASLoginView, CASCallbackClientView
|
||||
|
||||
urlpatterns = [
|
||||
path('login/', CASLoginView.as_view(), name='cas-login'),
|
||||
path('logout/', django_cas_ng.views.LogoutView.as_view(), name='cas-logout'),
|
||||
path('callback/', django_cas_ng.views.CallbackView.as_view(), name='cas-proxy-callback'),
|
||||
path('login/client', CASCallbackClientView.as_view(), name='cas-proxy-callback-client'),
|
||||
]
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
from django_cas_ng.views import LoginView
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.views.generic import View
|
||||
from django_cas_ng.views import LoginView
|
||||
|
||||
__all__ = ['LoginView']
|
||||
|
||||
from authentication.views.utils import redirect_to_guard_view
|
||||
|
||||
|
||||
class CASLoginView(LoginView):
|
||||
def get(self, request):
|
||||
|
@ -13,3 +16,8 @@ class CASLoginView(LoginView):
|
|||
return HttpResponseRedirect('/')
|
||||
|
||||
|
||||
class CASCallbackClientView(View):
|
||||
http_method_names = ['get', ]
|
||||
|
||||
def get(self, request):
|
||||
return redirect_to_guard_view(query_string='next=client')
|
||||
|
|
|
@ -4,9 +4,9 @@ from django.urls import path
|
|||
|
||||
from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('login/', views.OAuth2AuthRequestView.as_view(), name='login'),
|
||||
path('callback/', views.OAuth2AuthCallbackView.as_view(), name='login-callback'),
|
||||
path('callback/client/', views.OAuth2AuthCallbackClientView.as_view(), name='login-callback-client'),
|
||||
path('logout/', views.OAuth2EndSessionView.as_view(), name='logout')
|
||||
]
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
from django.views import View
|
||||
from django.conf import settings
|
||||
from django.contrib import auth
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse
|
||||
from django.utils.http import urlencode
|
||||
from django.views import View
|
||||
|
||||
from authentication.mixins import authenticate
|
||||
from authentication.utils import build_absolute_uri
|
||||
from authentication.views.mixins import FlashMessageMixin
|
||||
from authentication.mixins import authenticate
|
||||
from authentication.views.utils import redirect_to_guard_view
|
||||
from common.utils import get_logger
|
||||
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
||||
|
@ -67,6 +67,13 @@ class OAuth2AuthCallbackView(View, FlashMessageMixin):
|
|||
return HttpResponseRedirect(redirect_url)
|
||||
|
||||
|
||||
class OAuth2AuthCallbackClientView(View):
|
||||
http_method_names = ['get', ]
|
||||
|
||||
def get(self, request):
|
||||
return redirect_to_guard_view(query_string='next=client')
|
||||
|
||||
|
||||
class OAuth2EndSessionView(View):
|
||||
http_method_names = ['get', 'post', ]
|
||||
|
||||
|
|
|
@ -12,9 +12,9 @@ from django.urls import path
|
|||
|
||||
from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('login/', views.OIDCAuthRequestView.as_view(), name='login'),
|
||||
path('callback/', views.OIDCAuthCallbackView.as_view(), name='login-callback'),
|
||||
path('callback/client/', views.OIDCAuthCallbackClientView.as_view(), name='login-callback-client'),
|
||||
path('logout/', views.OIDCEndSessionView.as_view(), name='logout'),
|
||||
]
|
||||
|
|
|
@ -22,13 +22,14 @@ from django.http import HttpResponseRedirect, QueryDict
|
|||
from django.urls import reverse
|
||||
from django.utils.crypto import get_random_string
|
||||
from django.utils.http import urlencode
|
||||
from django.views.generic import View
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import View
|
||||
|
||||
from authentication.utils import build_absolute_uri_for_oidc
|
||||
from authentication.views.mixins import FlashMessageMixin
|
||||
from common.utils import safe_next_url
|
||||
from .utils import get_logger
|
||||
from ...views.utils import redirect_to_guard_view
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
@ -208,6 +209,13 @@ class OIDCAuthCallbackView(View, FlashMessageMixin):
|
|||
return HttpResponseRedirect(settings.AUTH_OPENID_AUTHENTICATION_FAILURE_REDIRECT_URI)
|
||||
|
||||
|
||||
class OIDCAuthCallbackClientView(View):
|
||||
http_method_names = ['get', ]
|
||||
|
||||
def get(self, request):
|
||||
return redirect_to_guard_view(query_string='next=client')
|
||||
|
||||
|
||||
class OIDCEndSessionView(View):
|
||||
""" Allows to end the session of any user authenticated using OpenID Connect.
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@ from django.urls import path
|
|||
|
||||
from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('login/', views.Saml2AuthRequestView.as_view(), name='saml2-login'),
|
||||
path('logout/', views.Saml2EndSessionView.as_view(), name='saml2-logout'),
|
||||
path('callback/', views.Saml2AuthCallbackView.as_view(), name='saml2-callback'),
|
||||
path('callback/client/', views.Saml2AuthCallbackClientView.as_view(), name='saml2-callback-client'),
|
||||
path('metadata/', views.Saml2AuthMetadataView.as_view(), name='saml2-metadata'),
|
||||
]
|
||||
|
|
|
@ -19,6 +19,7 @@ from onelogin.saml2.idp_metadata_parser import (
|
|||
from authentication.views.mixins import FlashMessageMixin
|
||||
from common.utils import get_logger
|
||||
from .settings import JmsSaml2Settings
|
||||
from ...views.utils import redirect_to_guard_view
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
@ -298,6 +299,13 @@ class Saml2AuthCallbackView(View, PrepareRequestMixin, FlashMessageMixin):
|
|||
return super().dispatch(*args, **kwargs)
|
||||
|
||||
|
||||
class Saml2AuthCallbackClientView(View):
|
||||
http_method_names = ['get', ]
|
||||
|
||||
def get(self, request):
|
||||
return redirect_to_guard_view(query_string='next=client')
|
||||
|
||||
|
||||
class Saml2AuthMetadataView(View, PrepareRequestMixin):
|
||||
|
||||
def get(self, request):
|
||||
|
|
|
@ -110,6 +110,9 @@ class BaseLoginCallbackView(AuthMixin, FlashMessageMixin, IMClientMixin, View):
|
|||
msg = e.msg
|
||||
response = self.get_failed_response(login_url, title=msg, msg=msg)
|
||||
return response
|
||||
|
||||
if 'next=client' in redirect_url:
|
||||
self.request.META['QUERY_STRING'] += '&next=client'
|
||||
return self.redirect_to_guard_view()
|
||||
|
||||
|
||||
|
|
|
@ -175,6 +175,8 @@ class DingTalkQRLoginView(DingTalkQRMixin, METAMixin, View):
|
|||
|
||||
def get(self, request: HttpRequest):
|
||||
redirect_url = request.GET.get('redirect_url') or reverse('index')
|
||||
query_string = request.GET.urlencode()
|
||||
redirect_url = f'{redirect_url}?{query_string}'
|
||||
next_url = self.get_next_url_from_meta() or reverse('index')
|
||||
next_url = safe_next_url(next_url, request=request)
|
||||
|
||||
|
|
|
@ -110,6 +110,8 @@ class FeiShuQRLoginView(FeiShuQRMixin, View):
|
|||
|
||||
def get(self, request: HttpRequest):
|
||||
redirect_url = request.GET.get('redirect_url') or reverse('index')
|
||||
query_string = request.GET.urlencode()
|
||||
redirect_url = f'{redirect_url}?{query_string}'
|
||||
redirect_uri = reverse(f'authentication:{self.category}-qr-login-callback', external=True)
|
||||
redirect_uri += '?' + urlencode({
|
||||
'redirect_url': redirect_url,
|
||||
|
|
|
@ -45,69 +45,70 @@ class UserLoginContextMixin:
|
|||
error_origin: str
|
||||
|
||||
def get_support_auth_methods(self):
|
||||
query_string = self.request.GET.urlencode()
|
||||
auth_methods = [
|
||||
{
|
||||
'name': 'OpenID',
|
||||
'enabled': settings.AUTH_OPENID,
|
||||
'url': reverse('authentication:openid:login'),
|
||||
'url': f"{reverse('authentication:openid:login')}?{query_string}",
|
||||
'logo': static('img/login_oidc_logo.png'),
|
||||
'auto_redirect': True # 是否支持自动重定向
|
||||
},
|
||||
{
|
||||
'name': 'CAS',
|
||||
'enabled': settings.AUTH_CAS,
|
||||
'url': reverse('authentication:cas:cas-login'),
|
||||
'url': f"{reverse('authentication:cas:cas-login')}?{query_string}",
|
||||
'logo': static('img/login_cas_logo.png'),
|
||||
'auto_redirect': True
|
||||
},
|
||||
{
|
||||
'name': 'SAML2',
|
||||
'enabled': settings.AUTH_SAML2,
|
||||
'url': reverse('authentication:saml2:saml2-login'),
|
||||
'url': f"{reverse('authentication:saml2:saml2-login')}?{query_string}",
|
||||
'logo': static('img/login_saml2_logo.png'),
|
||||
'auto_redirect': True
|
||||
},
|
||||
{
|
||||
'name': settings.AUTH_OAUTH2_PROVIDER,
|
||||
'enabled': settings.AUTH_OAUTH2,
|
||||
'url': reverse('authentication:oauth2:login'),
|
||||
'url': f"{reverse('authentication:oauth2:login')}?{query_string}",
|
||||
'logo': static_or_direct(settings.AUTH_OAUTH2_LOGO_PATH),
|
||||
'auto_redirect': True
|
||||
},
|
||||
{
|
||||
'name': _('WeCom'),
|
||||
'enabled': settings.AUTH_WECOM,
|
||||
'url': reverse('authentication:wecom-qr-login'),
|
||||
'url': f"{reverse('authentication:wecom-qr-login')}?{query_string}",
|
||||
'logo': static('img/login_wecom_logo.png'),
|
||||
},
|
||||
{
|
||||
'name': _('DingTalk'),
|
||||
'enabled': settings.AUTH_DINGTALK,
|
||||
'url': reverse('authentication:dingtalk-qr-login'),
|
||||
'url': f"{reverse('authentication:dingtalk-qr-login')}?{query_string}",
|
||||
'logo': static('img/login_dingtalk_logo.png')
|
||||
},
|
||||
{
|
||||
'name': _('FeiShu'),
|
||||
'enabled': settings.AUTH_FEISHU,
|
||||
'url': reverse('authentication:feishu-qr-login'),
|
||||
'url': f"{reverse('authentication:feishu-qr-login')}?{query_string}",
|
||||
'logo': static('img/login_feishu_logo.png')
|
||||
},
|
||||
{
|
||||
'name': 'Lark',
|
||||
'enabled': settings.AUTH_LARK,
|
||||
'url': reverse('authentication:lark-qr-login'),
|
||||
'url': f"{reverse('authentication:lark-qr-login')}?{query_string}",
|
||||
'logo': static('img/login_lark_logo.png')
|
||||
},
|
||||
{
|
||||
'name': _('Slack'),
|
||||
'enabled': settings.AUTH_SLACK,
|
||||
'url': reverse('authentication:slack-qr-login'),
|
||||
'url': f"{reverse('authentication:slack-qr-login')}?{query_string}",
|
||||
'logo': static('img/login_slack_logo.png')
|
||||
},
|
||||
{
|
||||
'name': _("Passkey"),
|
||||
'enabled': settings.AUTH_PASSKEY,
|
||||
'url': reverse('api-auth:passkey-login'),
|
||||
'url': f"{reverse('api-auth:passkey-login')}?{query_string}",
|
||||
'logo': static('img/login_passkey.png')
|
||||
}
|
||||
]
|
||||
|
@ -220,7 +221,7 @@ class UserLoginView(mixins.AuthMixin, UserLoginContextMixin, FormView):
|
|||
'redirect_url': redirect_url,
|
||||
'interval': 3,
|
||||
'has_cancel': True,
|
||||
'cancel_url': reverse('authentication:login') + '?admin=1'
|
||||
'cancel_url': reverse('authentication:login') + f'?admin=1&{query_string}'
|
||||
}
|
||||
redirect_url = FlashMessageUtil.gen_message_url(message_data)
|
||||
return redirect_url
|
||||
|
@ -306,6 +307,7 @@ class UserLoginGuardView(mixins.AuthMixin, RedirectView):
|
|||
login_url = reverse_lazy('authentication:login')
|
||||
login_mfa_url = reverse_lazy('authentication:login-mfa')
|
||||
login_confirm_url = reverse_lazy('authentication:login-wait-confirm')
|
||||
query_string = True
|
||||
|
||||
def format_redirect_url(self, url):
|
||||
args = self.request.META.get('QUERY_STRING', '')
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from django.views.generic.edit import FormView
|
||||
|
||||
from django.shortcuts import redirect, reverse
|
||||
from django.views.generic.edit import FormView
|
||||
|
||||
from common.utils import get_logger
|
||||
from users.views import UserFaceCaptureView
|
||||
from .. import forms, errors, mixins
|
||||
from .utils import redirect_to_guard_view
|
||||
from .. import forms, errors, mixins
|
||||
from ..const import MFAType
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
@ -48,7 +49,8 @@ class UserLoginMFAView(mixins.AuthMixin, FormView):
|
|||
self._do_check_user_mfa(code, mfa_type)
|
||||
user, ip = self.get_user_from_session(), self.get_request_ip()
|
||||
MFABlockUtils(user.username, ip).clean_failed_count()
|
||||
return redirect_to_guard_view('mfa_ok')
|
||||
query_string = self.request.GET.urlencode()
|
||||
return redirect_to_guard_view('mfa_ok', query_string)
|
||||
except (errors.MFAFailedError, errors.BlockMFAError) as e:
|
||||
form.add_error('code', e.msg)
|
||||
return super().form_invalid(form)
|
||||
|
|
|
@ -98,6 +98,8 @@ class SlackQRLoginView(SlackMixin, View):
|
|||
|
||||
def get(self, request: Request):
|
||||
redirect_url = request.GET.get('redirect_url') or reverse('index')
|
||||
query_string = request.GET.urlencode()
|
||||
redirect_url = f'{redirect_url}?{query_string}'
|
||||
redirect_uri = reverse('authentication:slack-qr-login-callback', external=True)
|
||||
redirect_uri += '?' + urlencode({
|
||||
'redirect_url': redirect_url,
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from urllib.parse import urlencode, parse_qsl
|
||||
|
||||
from django.shortcuts import reverse, redirect
|
||||
|
||||
|
||||
def redirect_to_guard_view(comment=''):
|
||||
continue_url = reverse('authentication:login-guard') + '?_=' + comment
|
||||
def redirect_to_guard_view(comment='', query_string=None):
|
||||
params = {'_': comment}
|
||||
base_url = reverse('authentication:login-guard')
|
||||
|
||||
if query_string:
|
||||
params.update(dict(parse_qsl(query_string)))
|
||||
|
||||
query_string = urlencode(params)
|
||||
|
||||
continue_url = f"{base_url}?{query_string}"
|
||||
return redirect(continue_url)
|
||||
|
|
|
@ -22,7 +22,6 @@ from users.views import UserVerifyPasswordView
|
|||
from .base import BaseLoginCallbackView, BaseBindCallbackView
|
||||
from .mixins import METAMixin, FlashMessageMixin
|
||||
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
||||
|
@ -86,6 +85,8 @@ class WeComQRBindView(WeComQRMixin, View):
|
|||
|
||||
def get(self, request: HttpRequest):
|
||||
redirect_url = request.GET.get('redirect_url')
|
||||
query_string = request.GET.urlencode()
|
||||
redirect_url = f'{redirect_url}?{query_string}'
|
||||
redirect_uri = reverse('authentication:wecom-qr-bind-callback', external=True)
|
||||
redirect_uri += '?' + urlencode({'redirect_url': redirect_url})
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import time
|
|||
|
||||
import pyotp
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import logout as auth_logout
|
||||
from django.core.cache import cache
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
|
@ -75,7 +74,6 @@ def redirect_user_first_login_or_index(request, redirect_field_name):
|
|||
|
||||
if url == 'client':
|
||||
url = get_redirect_client_url(request)
|
||||
auth_logout(request)
|
||||
|
||||
url = safe_next_url(url, request=request)
|
||||
# 防止 next 地址为 None
|
||||
|
|
Loading…
Reference in New Issue