- Frontend validates mobile number format client-side.
- Enitiates a GET request to the mobile validation endpoint.
- If the number is unregistered, enables the "Send Code" button.
- User submits verification code and password via POST to the registration endpoint.
- Backend verifies code against Redis cache, creates user, and returns token-secured response.
Mobile Number Validation Endpoint
This read-only API checks whether a given phone number is already associated with an active account.
# luffyapi/apps/user/urls.py
from django.urls import path
from . import views
urlpatterns = [
# ...
path('check-mobile/', views.MobileAvailabilityCheck.as_view()),
]
# luffyapi/apps/user/views.py
import re
from rest_framework.views import APIView
from rest_framework.response import Response
from . import models
class MobileAvailabilityCheck(APIView):
def get(self, request):
number = request.query_params.get('mobile', '').strip()
if not number:
return Response({'code': 1, 'message': 'Mobile number is required'}, status=400)
if not re.fullmatch(r'1[3-9]\d{9}', number):
return Response({'code': 1, 'message': 'Invalid mobile format'}, status=400)
exists = models.User.objects.filter(mobile=number, is_active=True).exists()
return Response({
'code': 0 if not exists else 2,
'message': 'Available' if not exists else 'Already registered'
})
Mobile-Based User Registration
Accepts mobile number, six-digit numeric code, and password; performs validation and persists user securely.
# luffyapi/apps/user/urls.py
urlpatterns += [
path('register-by-mobile/', views.MobileRegistrationView.as_view()),
]
# luffyapi/apps/user/views.py
from rest_framework.generics import CreateAPIView
from django.contrib.auth import get_user_model
from django.core.cache import cache
from . import my_serializers, settings
User = get_user_model()
class MobileRegistrationView(CreateAPIView):
serializer_class = my_serializers.MobileRegistrationSerializer
def create(self, request, *args, **kwargs):
response = super().create(request, *args, **kwargs)
response.data.pop('password', None)
return response
# luffyapi/apps/user/my_serializers.py
import re
import django.core.cache as cache_module
from rest_framework import serializers
from . import models, settings
class MobileRegistrationSerializer(serializers.Serializer):
mobile = serializers.CharField()
code = serializers.RegexField(r'^\d{6}$', write_only=True)
password = serializers.CharField(min_length=8)
def validate_mobile(self, value):
if not re.fullmatch(r'1[3-9]\d{9}', value):
raise serializers.ValidationError('Invalid mobile number')
return value
def validate_code(self, value):
mobile = self.initial_data.get('mobile')
cached = cache_module.cache.get(settings.SMS_CODE_CACHE_KEY.format(mobile))
if cached != value:
raise serializers.ValidationError('Invalid or expired verification code')
return value
def create(self, validated_data):
mobile = validated_data['mobile']
user = User.objects.create_user(
username=mobile,
mobile=mobile,
password=validated_data['password']
)
cache_module.cache.delete(settings.SMS_CODE_CACHE_KEY.format(mobile))
return user
JWT Authentication and Per-Mobile SMS Throttling
Global JWT configuration ensures all endpoints require valid tokens by default. SMS sending is restritced per mobile number using custom throttling logic.
# luffyapi/settings/dev_settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
],
'DEFAULT_THROTTLE_RATES': {
'sms_per_mobile': '1/min',
}
}
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': timedelta(days=1),
}
# luffyapi/apps/user/throttles.py
from rest_framework.throttling import SimpleRateThrottle
class MobileCodeThrottle(SimpleRateThrottle):
scope = 'sms_per_mobile'
def get_cache_key(self, request, view):
mobile = request.query_params.get('mobile') or request.data.get('mobile')
if not mobile:
return None
return f'sms_throttle_{mobile}'
# luffyapi/apps/user/views.py
from rest_framework.views import APIView
from .throttles import MobileCodeThrottle
class SmsDispatchView(APIView):
throttle_classes = [MobileCodeThrottle]
def get(self, request):
mobile = request.query_params.get('mobile')
# ... generate & cache 6-digit code, send via SMS gateway
return Response({'status': 'sent'})
Client-Side Cookie Management in Vue.js
Use vue-cookies to persist authentication tokens or session identifiers across page reloads.
# Install
npm install vue-cookies
# Register globally in main.js
import Vue from 'vue';
import VueCookies from 'vue-cookies';
Vue.use(VueCookies);
# Usage in components
this.$cookies.set('auth_token', jwtToken, '1d'); // expires in 1 day
const token = this.$cookies.get('auth_token');
this.$cookies.remove('auth_token');