1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-08-02 19:55:18 +02:00

feat: Implement disable password authentication for users with social accounts

This commit is contained in:
Sean Morley 2025-03-16 21:49:00 -04:00
parent 189cd0ee69
commit a38828eb45
14 changed files with 184 additions and 17 deletions

View file

@ -0,0 +1,16 @@
from django.contrib.auth.backends import ModelBackend
from allauth.socialaccount.models import SocialAccount
class NoPasswordAuthBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
print("NoPasswordAuthBackend")
# First, attempt normal authentication
user = super().authenticate(request, username=username, password=password, **kwargs)
if user is None:
return None
if SocialAccount.objects.filter(user=user).exists() and user.disable_password:
# If yes, disable login via password
return None
return user

View file

@ -0,0 +1,18 @@
# Generated by Django 5.0.8 on 2025-03-17 01:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0003_alter_customuser_email'),
]
operations = [
migrations.AddField(
model_name='customuser',
name='disable_password',
field=models.BooleanField(default=False),
),
]

View file

@ -8,6 +8,7 @@ class CustomUser(AbstractUser):
profile_pic = ResizedImageField(force_format="WEBP", quality=75, null=True, blank=True, upload_to='profile-pics/')
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
public_profile = models.BooleanField(default=False)
disable_password = models.BooleanField(default=False)
def __str__(self):
return self.username

View file

@ -64,9 +64,11 @@ class UserDetailsSerializer(serializers.ModelSerializer):
extra_fields.append('date_joined')
if hasattr(UserModel, 'is_staff'):
extra_fields.append('is_staff')
if hasattr(UserModel, 'disable_password'):
extra_fields.append('disable_password')
fields = ['pk', *extra_fields]
read_only_fields = ('email', 'date_joined', 'is_staff', 'is_superuser', 'is_active', 'pk')
read_only_fields = ('email', 'date_joined', 'is_staff', 'is_superuser', 'is_active', 'pk', 'disable_password')
def handle_public_profile_change(self, instance, validated_data):
"""
@ -95,7 +97,7 @@ class CustomUserDetailsSerializer(UserDetailsSerializer):
class Meta(UserDetailsSerializer.Meta):
model = CustomUser
fields = UserDetailsSerializer.Meta.fields + ['profile_pic', 'uuid', 'public_profile', 'has_password']
read_only_fields = UserDetailsSerializer.Meta.read_only_fields + ('uuid', 'has_password')
read_only_fields = UserDetailsSerializer.Meta.read_only_fields + ('uuid', 'has_password', 'disable_password')
@staticmethod
def get_has_password(instance):

View file

@ -13,6 +13,7 @@ from .serializers import CustomUserDetailsSerializer as PublicUserSerializer
from allauth.socialaccount.models import SocialApp
from adventures.serializers import AdventureSerializer, CollectionSerializer
from adventures.models import Adventure, Collection
from allauth.socialaccount.models import SocialAccount
User = get_user_model()
@ -171,4 +172,35 @@ class EnabledSocialProvidersView(APIView):
'url': f"{getenv('PUBLIC_URL')}/accounts/{new_provider}/login/",
'name': provider.name
})
return Response(providers, status=status.HTTP_200_OK)
return Response(providers, status=status.HTTP_200_OK)
class DisablePasswordAuthenticationView(APIView):
"""
Disable password authentication for a user. This is used when a user signs up with a social provider.
"""
# Allows the user to set the disable_password field to True if they have a social account linked
permission_classes = [IsAuthenticated]
@swagger_auto_schema(
responses={
200: openapi.Response('Password authentication disabled'),
400: 'Bad Request'
},
operation_description="Disable password authentication."
)
def post(self, request):
user = request.user
if SocialAccount.objects.filter(user=user).exists():
user.disable_password = True
user.save()
return Response({"detail": "Password authentication disabled."}, status=status.HTTP_200_OK)
return Response({"detail": "No social account linked."}, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request):
user = request.user
user.disable_password = False
user.save()
return Response({"detail": "Password authentication enabled."}, status=status.HTTP_200_OK)