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, redirect
from users.models import AuthCode
import uuid
from django.utils.decorators import method_decorator
from django.contrib.auth.models import User
from django.views.decorators.csrf import csrf_exempt
from backend import settings
from django.contrib.auth import get_user_model
from django.contrib.auth import authenticate, login
User = get_user_model()
class GenerateTelegramCodeView(View):
def get(self, request, *args, **kwargs):
# Устанавливаем время истечения кода на 5 минут в будущее
expiry_time = timezone.now() + timezone.timedelta(minutes=5)
# Создаём новый код с установленным временем истечения
new_code = AuthCode.objects.create(
session_id=request.session.session_key, expiry_time=expiry_time
)
# Возвращаем созданный код как JSON
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")
try:
auth_code = AuthCode.objects.get(code=code, expiry_time__gt=timezone.now())
if auth_code:
auth_code.is_used = True
user = authenticate(request, telegram_id=telegram_id)
if user is None:
user = User.objects.create_user(telegram_id=telegram_id)
user = 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_code = AuthCode.objects.filter(
session_id=request.session.session_key, expiry_time__gt=timezone.now()
).first()
if auth_code.telegram_id is not None:
user = authenticate(request, telegram_id=auth_code.telegram_id)
if user is not None:
print(user.is_active)
login(request, user)
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/urls.py
from django.urls import path
from . import views
app_name = 'users'
urlpatterns = [
path('telegram_auth/generate_code/', views.GenerateTelegramCodeView.as_view(), name='generate_telegram_code'),
path('telegram_auth/', views.TelegramAuthView.as_view(), name='telegram_auth'),
path('auth/', views.AuthenticateView.as_view(), name='authenticate'),
]
#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 = []
# Изменение related_name для каждого поля, чтобы избежать конфликта
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', // Явное указание, что это POST-запрос
headers: {
'Content-Type': 'application/json',
// Добавьте 'X-CSRF-Token': 'токен' если CSRF защита включена
},
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));
}
// Установка интервала для периодической проверки статуса входа
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/xkiks_bot?start=${data.code}`, '_blank');
// Закрыть модальное окно
document.getElementById('loginModal').style.display = 'none';
// Задержка перед перенаправлением, чтобы у пользователя было время увидеть открытие новой вкладки
setTimeout(function() {
window.location.href = "/users/auth/";
}, 1000); // Задержка в 1000 миллисекунд (1 секунда)
})
.catch(error => {
console.error('Error:', error);
alert('Произошла ошибка при попытке получить код доступа.');
});
}
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('Успешный вход');
// Вы можете перенаправить пользователя или обновить UI, например:
// window.location.href = '/profile';
} 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