I am writing a site with a custom user model. I want to access the site via telegram. Everything works, but the authentication itself - the login function does nothing(
I don’t understand what’s wrong, I’ve been trying different ways for 3 days now, but nothing works. I will be glad to any advice. And here is my code
#users/views.py
from django.http import JsonResponse
from django.views import View
from django.utils import timezone
from django.shortcuts import render
from users.models import AuthCode
from django.utils.decorators import method_decorator
from django.contrib.auth.models import User
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth import login, get_user_model
from users.backend import TelegramAuthBackend
User = get_user_model()
class GenerateTelegramCodeView(View):
def get(self, request, *args, **kwargs):
expiry_time = timezone.now() + timezone.timedelta(minutes=5)
new_code = AuthCode.objects.create(
session_id=request.session.session_key, expiry_time=expiry_time
)
return JsonResponse({"code": str(new_code.code)})
@method_decorator(csrf_exempt, name="dispatch")
class TelegramAuthView(View):
def post(self, request, *args, **kwargs):
telegram_id = request.POST.get("telegram_id")
code = request.POST.get("code")
auth_backend = TelegramAuthBackend()
try:
auth_code = AuthCode.objects.get(code=code, expiry_time__gt=timezone.now())
if auth_code:
auth_code.is_used = True
user = auth_backend.authenticate(request, telegram_id=telegram_id)
if user is None:
user = User.objects.create_user(telegram_id=telegram_id)
user = auth_backend.authenticate(request, telegram_id=telegram_id)
if user:
auth_code.telegram_id = telegram_id
auth_code.save()
return JsonResponse({"status": "ok", "message": "Ok!"}, status=200)
else:
return JsonResponse(
{"status": "error", "message": "Authentication failed"},
status=403,
)
else:
return JsonResponse(
{"status": "error", "message": "Invalid or expired code"},
status=400,
)
except AuthCode.DoesNotExist:
return JsonResponse(
{"status": "error", "message": "Code not found"}, status=404
)
@method_decorator(csrf_exempt, name="dispatch")
class AuthenticateView(View):
def post(self, request, *args, **kwargs):
auth_backend = TelegramAuthBackend()
auth_code = AuthCode.objects.filter(
session_id=request.session.session_key, expiry_time__gt=timezone.now()
).first()
print(auth_code)
if auth_code.telegram_id is not None:
user = auth_backend.authenticate(request, telegram_id=auth_code.telegram_id)
if user is not None:
login(request, user, backend='users.backend.TelegramAuthBackend')
return JsonResponse({"isLoggedIn": True, "message": "Ok."})
else:
return JsonResponse(
{"isLoggedIn": False, "message": "User is not logged in."}
)
def get(self, request, *args, **kwargs):
return render(request, "users/authenticate.html")
#users/backend.py
from django.contrib.auth.backends import BaseBackend
from django.contrib.auth import get_user_model
import logging
logger = logging.getLogger(__name__)
class TelegramAuthBackend(BaseBackend):
def authenticate(self, request, telegram_id=None):
logger.debug(f"Trying to authenticate user with telegram_id={telegram_id}")
UserModel = get_user_model()
try:
user = UserModel.objects.get(telegram_id=telegram_id, is_active=True)
logger.debug("User found and is active")
return user
except UserModel.DoesNotExist:
logger.debug("User not found")
return None
#users/models.py
from django.db import models
import uuid
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models
from django.utils.translation import gettext_lazy as _
class AuthCode(models.Model):
code = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
session_id = models.CharField(max_length=50, null=True, blank=True)
telegram_id = models.CharField(max_length=50, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
expiry_time = models.DateTimeField()
is_used = models.BooleanField(default=False)
def __str__(self):
return f"{self.code} - Expires at {self.expiry_time}"
class CustomUserManager(BaseUserManager):
def create_user(self, telegram_id, password=None, **extra_fields):
if not telegram_id:
raise ValueError(_('The Telegram ID must be set'))
user = self.model(telegram_id=telegram_id, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, telegram_id, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
return self.create_user(telegram_id, password, **extra_fields)
class CustomUser(AbstractBaseUser, PermissionsMixin):
telegram_id = models.CharField(_('Telegram ID'), unique=True, max_length=50)
is_active = models.BooleanField(_('Active'), default=True)
is_staff = models.BooleanField(_('Staff status'), default=False)
objects = CustomUserManager()
USERNAME_FIELD = 'telegram_id'
REQUIRED_FIELDS = []
groups = models.ManyToManyField(
'auth.Group',
verbose_name=_('groups'),
blank=True,
help_text=_('The groups this user belongs to. A user will get all permissions granted to each of their groups.'),
related_name="customuser_set",
related_query_name="customuser",
)
user_permissions = models.ManyToManyField(
'auth.Permission',
verbose_name=_('user permissions'),
blank=True,
help_text=_('Specific permissions for this user.'),
related_name="customuser_set",
related_query_name="customuser",
)
def __str__(self):
return self.telegram_id
#authenticate.html (script)
<script>
function checkLoginStatus() {
fetch('/users/auth/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include'
})
.then(response => response.json())
.then(data => {
if (data.isLoggedIn) {
console.log(data.message);
clearInterval(loginStatusInterval);
window.location.href = "/";
} else {
console.log(data.message);
}
})
.catch(error => console.error('Error:', error));
}
let loginStatusInterval = setInterval(checkLoginStatus, 1000);
</script>
#base.html (script)
<script>
function openLoginModal() {
document.getElementById('loginModal').style.display = 'block';
}
function getTelegramCode() {
fetch('/users/telegram_auth/generate_code/')
.then(response => response.json())
.then(data => {
window.open(`https://t.me/bot_name?start=${data.code}`, '_blank');
document.getElementById('loginModal').style.display = 'none';
setTimeout(function() {
window.location.href = "/users/auth/";
}, 1000);
})
.catch(error => {
console.error('Error:', error);
alert('We had an error.');
});
}
function authenticateUser(telegram_id, code) {
fetch('/users/telegram_auth/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ telegram_id: telegram_id, code: code })
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
alert('Success');
} else {
alert(data.message);
}
})
.catch(error => console.error('Error:', error));
}
</script>
I read the official documentation and tried to understand the source code. But I didn’t find anything suspicious there