← Назад к вопросам
Как происходит авторизация?
2.0 Middle🔥 211 комментариев
#REST API и HTTP#Безопасность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как происходит авторизация
Авторизация — это процесс определения того, какие действия может выполнять аутентифицированный пользователь. Это отличается от аутентификации, которая проверяет личность пользователя.
1. Основной процесс авторизации
Авторизация обычно происходит в три этапа:
# 1. Аутентификация — кто ты?
user = authenticate(username='john', password='secret')
# 2. Авторизация — что ты можешь делать?
if user and user.has_perm('posts.delete_post'):
# 3. Выполнение действия
post.delete()
else:
raise PermissionError('Нет прав на удаление поста')
2. Авторизация на основе ролей (RBAC)
Это самый распространённый подход — пользователь имеет роль, роль имеет набор прав.
from django.contrib.auth.models import User, Group, Permission
from django.contrib.contenttypes.models import ContentType
# Создаём роли и права
class User(models.Model):
username = models.CharField(max_length=100)
role = models.ForeignKey(Role, on_delete=models.CASCADE)
class Role(models.Model):
name = models.CharField(max_length=100) # 'admin', 'moderator', 'user'
permissions = models.ManyToManyField(Permission)
# Проверка прав
def can_delete_post(user, post):
return user.role.permissions.filter(codename='delete_post').exists()
# Использование
if can_delete_post(request.user, post):
post.delete()
3. Авторизация на основе атрибутов (ABAC)
Права зависят от атрибутов пользователя, ресурса и контекста.
class Post(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(User, on_delete=models.CASCADE)
is_published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
def can_edit_post(user, post):
# ABAC логика
checks = [
user.id == post.author_id, # автор может редактировать
user.role.name == 'admin', # админ может всё
(user.role.name == 'moderator' and post.is_published), # модератор — опубликованные
(datetime.now() - post.created_at).days < 30, # можно редактировать 30 дней
]
return any(checks)
4. Django встроенная система прав
from django.contrib.auth.decorators import permission_required
from django.views.decorators.http import require_http_methods
# Декоратор на функцию представления
@permission_required('posts.delete_post')
def delete_post(request, post_id):
post = Post.objects.get(id=post_id)
post.delete()
return redirect('posts:list')
# В классе представления
from django.contrib.auth.mixins import PermissionRequiredMixin
class DeletePostView(PermissionRequiredMixin, DeleteView):
model = Post
permission_required = 'posts.delete_post'
success_url = reverse_lazy('posts:list')
# Проверка в представлении
if request.user.has_perm('posts.view_post'):
# показываем пост
pass
# Проверка на уровне QuerySet (фильтрация)
posts = Post.objects.filter(
Q(author=request.user) | # свои посты
Q(is_published=True, author__role__name='admin') # опубликованные админа
)
5. API авторизация (Token/JWT)
Token Based Auth
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
# Получить токен
from rest_framework.authtoken.views import obtain_auth_token
# settings.py
INSTALLED_APPS = ['rest_framework.authtoken']
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework.authentication.TokenAuthentication'],
}
# Использование в API
@api_view(['GET'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def get_profile(request):
return Response({'user': request.user.username})
# Client отправляет токен
# curl -H 'Authorization: Token 12345abcde' http://api.example.com/profile/
JWT (JSON Web Token)
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework.permissions import IsAuthenticated
# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework_simplejwt.authentication.JWTAuthentication'],
}
# urls.py
urlpatterns = [
path('api/token/', TokenObtainPairView.as_view()), # POST вернёт access + refresh токены
path('api/token/refresh/', TokenRefreshView.as_view()), # обновить access
]
# Использование
@api_view(['POST'])
@authentication_classes([JWTAuthentication])
@permission_classes([IsAuthenticated])
def protected_view(request):
return Response({'message': 'Вы авторизованы'})
# Client отправляет JWT
# curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGc...' http://api.example.com/protected/
6. OAuth 2.0 авторизация (через внешних поставщиков)
from social_django.models import UserSocialAuth
from allauth.socialaccount.models import SocialAccount
# settings.py
INSTALLED_APPS = [
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.google',
'allauth.socialaccount.providers.github',
]
# Пользователь авторизуется через Google
# 1. На фронте перенаправляем на Google
# 2. Google возвращает код
# 3. Мы обмениваем код на токен
# 4. Получаем информацию пользователя
# 5. Создаём или обновляем пользователя в нашей БД
def google_auth_callback(request):
code = request.GET.get('code')
# Обмениваем code на токен
token_response = requests.post(
'https://oauth2.googleapis.com/token',
data={
'client_id': settings.GOOGLE_CLIENT_ID,
'client_secret': settings.GOOGLE_CLIENT_SECRET,
'code': code,
'redirect_uri': 'http://localhost:8000/auth/callback/'
}
)
access_token = token_response.json()['access_token']
# Получаем данные пользователя
user_info = requests.get(
'https://www.googleapis.com/oauth2/v1/userinfo',
headers={'Authorization': f'Bearer {access_token}'}
).json()
# Создаём или обновляем пользователя
user, created = User.objects.get_or_create(
email=user_info['email'],
defaults={'username': user_info['given_name']}
)
# Логируем пользователя
request.session['user_id'] = user.id
return redirect('home')
7. Кастомная авторизация с декораторами
from functools import wraps
from django.http import HttpResponseForbidden
def require_role(role_name):
"""Проверяет наличие роли у пользователя"""
def decorator(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
if not request.user.is_authenticated:
return redirect('login')
if request.user.role.name != role_name:
return HttpResponseForbidden('Access denied')
return view_func(request, *args, **kwargs)
return wrapper
return decorator
def require_any_role(*role_names):
"""Проверяет что роль пользователя входит в список"""
def decorator(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
if not request.user.is_authenticated:
return redirect('login')
if request.user.role.name not in role_names:
return HttpResponseForbidden('Access denied')
return view_func(request, *args, **kwargs)
return wrapper
return decorator
# Использование
@require_role('admin')
def admin_panel(request):
return render(request, 'admin/panel.html')
@require_any_role('admin', 'moderator')
def moderate_posts(request):
return render(request, 'admin/posts.html')
8. Авторизация на уровне QuerySet
class PostQuerySet(models.QuerySet):
def for_user(self, user):
"""Фильтрует посты в зависимости от прав пользователя"""
if user.is_superuser:
return self
if user.role.name == 'admin':
return self
if user.role.name == 'moderator':
return self.filter(is_published=True)
# Обычный пользователь видит только свои посты и опубликованные
return self.filter(
Q(author=user) | Q(is_published=True)
)
class Post(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(User, on_delete=models.CASCADE)
is_published = models.BooleanField(default=False)
objects = PostQuerySet.as_manager()
# Использование
posts = Post.objects.for_user(request.user) # автоматическая фильтрация
9. Авторизация в Django REST Framework
from rest_framework.permissions import BasePermission
class IsPostAuthor(BasePermission):
"""Только автор может редактировать пост"""
def has_object_permission(self, request, view, obj):
return obj.author == request.user
class IsAdminOrReadOnly(BasePermission):
"""Админ может писать, остальные только читать"""
def has_permission(self, request, view):
if request.method in ['GET', 'HEAD', 'OPTIONS']:
return True
return request.user and request.user.is_staff
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
permission_classes = [IsAdminOrReadOnly, IsPostAuthor]
def get_queryset(self):
# Фильтруем посты по правам
return Post.objects.for_user(self.request.user)
Мои рекомендации
- Используй Django встроенные системы для простых случаев
- Для API — JWT токены вместо session cookies
- Проверяй права на уровне QuerySet чтобы не утекли данные
- Используй классные permissions в DRF (не проверяй в view)
- Логируй попытки несанкционированного доступа для безопасности
- Кешируй результаты проверки прав если они дорогие
- RBAC простое и понятное — используй его по умолчанию