Browse Source

perf: 修改用户确认

pull/11885/head
ibuler 1 year ago
parent
commit
452ee1224c
  1. 17
      apps/authentication/api/confirm.py
  2. 15
      apps/authentication/backends/passkey/api.py
  3. 1
      apps/authentication/confirm/relogin.py
  4. 1
      apps/authentication/const.py
  5. 2
      apps/authentication/serializers/confirm.py
  6. 2
      apps/authentication/urls/api_urls.py
  7. 3
      apps/common/exceptions.py

17
apps/authentication/api/confirm.py

@ -4,10 +4,12 @@ import time
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from rest_framework import status from rest_framework import status
from rest_framework.generics import RetrieveAPIView, CreateAPIView from rest_framework.decorators import action
from rest_framework.generics import RetrieveAPIView
from rest_framework.response import Response from rest_framework.response import Response
from authentication.permissions import UserConfirmation from authentication.permissions import UserConfirmation
from common.api import JMSGenericViewSet
from common.permissions import IsValidUser from common.permissions import IsValidUser
from ..const import ConfirmType from ..const import ConfirmType
from ..serializers import ConfirmSerializer from ..serializers import ConfirmSerializer
@ -20,10 +22,17 @@ class ConfirmBindORUNBindOAuth(RetrieveAPIView):
return Response('ok') return Response('ok')
class ConfirmApi(RetrieveAPIView, CreateAPIView): class UserConfirmationViewSet(JMSGenericViewSet):
permission_classes = (IsValidUser,) permission_classes = (IsValidUser,)
serializer_class = ConfirmSerializer serializer_class = ConfirmSerializer
@action(methods=['get'], detail=False)
def check(self, request):
confirm_type = request.query_params.get('confirm_type', 'password')
permission = UserConfirmation.require(confirm_type)()
permission.has_permission(request, self)
return Response('ok')
def get_confirm_backend(self, confirm_type): def get_confirm_backend(self, confirm_type):
backend_classes = ConfirmType.get_prop_backends(confirm_type) backend_classes = ConfirmType.get_prop_backends(confirm_type)
if not backend_classes: if not backend_classes:
@ -34,12 +43,12 @@ class ConfirmApi(RetrieveAPIView, CreateAPIView):
continue continue
return backend return backend
def retrieve(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
confirm_type = request.query_params.get('confirm_type', 'password') confirm_type = request.query_params.get('confirm_type', 'password')
backend = self.get_confirm_backend(confirm_type) backend = self.get_confirm_backend(confirm_type)
if backend is None: if backend is None:
msg = _('This action require verify your MFA') msg = _('This action require verify your MFA')
return Response(data={'error': msg}, status=status.HTTP_404_NOT_FOUND) return Response(data={'error': msg}, status=status.HTTP_400_BAD_REQUEST)
data = { data = {
'confirm_type': backend.name, 'confirm_type': backend.name,

15
apps/authentication/backends/passkey/api.py

@ -4,19 +4,30 @@ from django.shortcuts import render
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.viewsets import ModelViewSet
from authentication.mixins import AuthMixin from authentication.mixins import AuthMixin
from common.api import JMSModelViewSet
from .fido import register_begin, register_complete, auth_begin, auth_complete from .fido import register_begin, register_complete, auth_begin, auth_complete
from .models import Passkey from .models import Passkey
from .serializer import PasskeySerializer from .serializer import PasskeySerializer
from ...const import ConfirmType
from ...permissions import UserConfirmation
from ...views import FlashMessageMixin from ...views import FlashMessageMixin
class PasskeyViewSet(AuthMixin, FlashMessageMixin, ModelViewSet): class PasskeyViewSet(AuthMixin, FlashMessageMixin, JMSModelViewSet):
serializer_class = PasskeySerializer serializer_class = PasskeySerializer
permission_classes = (IsAuthenticated,) permission_classes = (IsAuthenticated,)
def get_permissions(self):
if self.is_swagger_request():
return super().get_permissions()
if self.action == 'register':
self.permission_classes = [
IsAuthenticated, UserConfirmation.require(ConfirmType.PASSWORD)
]
return super().get_permissions()
def get_queryset(self): def get_queryset(self):
return Passkey.objects.filter(user=self.request.user) return Passkey.objects.filter(user=self.request.user)

1
apps/authentication/confirm/relogin.py

@ -15,6 +15,7 @@ class ConfirmReLogin(BaseConfirm):
display_name = 'Re-Login' display_name = 'Re-Login'
def check(self): def check(self):
return True
return not self.user.is_password_authenticate() return not self.user.is_password_authenticate()
def authenticate(self, secret_key, mfa_type): def authenticate(self, secret_key, mfa_type):

1
apps/authentication/const.py

@ -19,6 +19,7 @@ class ConfirmType(TextChoices):
def get_can_confirm_types(cls, confirm_type): def get_can_confirm_types(cls, confirm_type):
start = cls.values.index(confirm_type) start = cls.values.index(confirm_type)
types = cls.values[start:] types = cls.values[start:]
types = [tp for tp in types if tp != 'password']
types.reverse() types.reverse()
return types return types

2
apps/authentication/serializers/confirm.py

@ -7,4 +7,4 @@ from ..const import ConfirmType, MFAType
class ConfirmSerializer(serializers.Serializer): class ConfirmSerializer(serializers.Serializer):
confirm_type = serializers.ChoiceField(required=True, allow_blank=True, choices=ConfirmType.choices) confirm_type = serializers.ChoiceField(required=True, allow_blank=True, choices=ConfirmType.choices)
mfa_type = serializers.ChoiceField(required=False, allow_blank=True, choices=MFAType.choices) mfa_type = serializers.ChoiceField(required=False, allow_blank=True, choices=MFAType.choices)
secret_key = EncryptedField(allow_blank=True) secret_key = EncryptedField(allow_blank=True, required=False)

2
apps/authentication/urls/api_urls.py

@ -13,6 +13,7 @@ router.register('sso', api.SSOViewSet, 'sso')
router.register('temp-tokens', api.TempTokenViewSet, 'temp-token') router.register('temp-tokens', api.TempTokenViewSet, 'temp-token')
router.register('connection-token', api.ConnectionTokenViewSet, 'connection-token') router.register('connection-token', api.ConnectionTokenViewSet, 'connection-token')
router.register('super-connection-token', api.SuperConnectionTokenViewSet, 'super-connection-token') router.register('super-connection-token', api.SuperConnectionTokenViewSet, 'super-connection-token')
router.register('confirm', api.UserConfirmationViewSet, 'confirm')
urlpatterns = [ urlpatterns = [
path('wecom/qr/unbind/', api.WeComQRUnBindForUserApi.as_view(), name='wecom-qr-unbind'), path('wecom/qr/unbind/', api.WeComQRUnBindForUserApi.as_view(), name='wecom-qr-unbind'),
@ -29,7 +30,6 @@ urlpatterns = [
name='feishu-event-subscription-callback'), name='feishu-event-subscription-callback'),
path('auth/', api.TokenCreateApi.as_view(), name='user-auth'), path('auth/', api.TokenCreateApi.as_view(), name='user-auth'),
path('confirm/', api.ConfirmApi.as_view(), name='user-confirm'),
path('confirm-oauth/', api.ConfirmBindORUNBindOAuth.as_view(), name='confirm-oauth'), path('confirm-oauth/', api.ConfirmBindORUNBindOAuth.as_view(), name='confirm-oauth'),
path('tokens/', api.TokenCreateApi.as_view(), name='auth-token'), path('tokens/', api.TokenCreateApi.as_view(), name='auth-token'),
path('mfa/verify/', api.MFAChallengeVerifyApi.as_view(), name='mfa-verify'), path('mfa/verify/', api.MFAChallengeVerifyApi.as_view(), name='mfa-verify'),

3
apps/common/exceptions.py

@ -42,8 +42,11 @@ class ReferencedByOthers(JMSException):
class UserConfirmRequired(JMSException): class UserConfirmRequired(JMSException):
status_code = status.HTTP_412_PRECONDITION_FAILED
def __init__(self, code=None): def __init__(self, code=None):
detail = { detail = {
'type': 'user_confirm_required',
'code': code, 'code': code,
'detail': _('This action require confirm current user') 'detail': _('This action require confirm current user')
} }

Loading…
Cancel
Save