Какие основные подходы к реализации авторизации в веб-приложениях на Python?

Ответ

Авторизацию важно не путать с аутентификацией:

  • Аутентификация (Authentication): Проверка, кем является пользователь (например, по логину и паролю).
  • Авторизация (Authorization): Проверка, имеет ли аутентифицированный пользователь право на выполнение определённого действия.

Основные модели авторизации:

  1. RBAC (Role-Based Access Control): Доступ предоставляется на основе ролей (admin, user, guest). Это самый распространённый подход.
  2. ACL (Access Control Lists): Права доступа назначаются конкретным пользователям для конкретных объектов.
  3. ABAC (Attribute-Based Access Control): Более гибкая модель, где доступ определяется на основе атрибутов пользователя, объекта и окружения (например, время суток).

Практическая реализация:

Авторизация обычно выполняется после успешной аутентификации. Информация о ролях или правах пользователя часто хранится в JWT (JSON Web Token) или в серверной сессии.

Пример декоратора для проверки роли в Flask (с использованием JWT):

from functools import wraps
from flask import request, jsonify
import jwt

# Предполагается, что токен содержит payload вида {'user': 'test', 'role': 'admin'}
SECRET_KEY = 'your-secret-key'

def role_required(role_name):
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            token = request.headers.get('Authorization')
            if not token:
                return jsonify({'message': 'Токен отсутствует'}), 401
            try:
                # Убираем 'Bearer '
                token = token.split()[1]
                payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
                # Проверяем наличие нужной роли
                if payload.get('role') != role_name:
                    return jsonify({'message': 'Недостаточно прав'}), 403
            except (jwt.ExpiredSignatureError, jwt.InvalidTokenError):
                return jsonify({'message': 'Невалидный токен'}), 401
            return f(*args, **kwargs)
        return decorated_function
    return decorator

@app.route('/admin/dashboard')
@role_required('admin')
def admin_dashboard():
    return 'Добро пожаловать в панель администратора!'

Современные фреймворки, такие как Django REST Framework (Permission Classes) и FastAPI (Dependencies), предоставляют встроенные и расширяемые инструменты для реализации этих моделей.

Ответ 18+ 🔞

Давай разберём эту тему, а то народ постоянно путает, как будто у них в голове вместо мозгов — хуй с горы.

Смотри, есть две штуки, которые все время мешают в одну кучу: аутентификация и авторизация.

Аутентификация — это когда ты доказываешь, что ты это ты. Типа: «Эй, я Вася!» — «А ну-ка, Вася, пароль скажи!» — «12345». — «О, точно Вася, заходи». Вот это вот «заходи» — это аутентификация, ёпта. Проверили, кто ты есть.

А авторизация — это уже другая история. Это когда ты уже внутри, Вася, и пытаешься что-то сделать. И система тебе говорит: «Вася, ты конечно Вася, но нахуй ты лезешь в админку? Ты же юзер, блядь!». То есть проверка прав: можно ли тебе это делать или нет. Понимаешь разницу? В рот меня чих-пых, народ путает!

Теперь, как это всё устроено. Есть три основных подхода, как права раздавать:

  1. RBAC (Ролевой доступ) — самый простой и популярный. Ты не к каждому челу привязываешь права, а создаёшь роли: admin, user, guest. И говоришь: «Все, кто в роли admin — могут всё, а user — только своё». Как в армии: генерал — командует, рядовой — подметает.

  2. ACL (Списки контроля доступа) — это уже точечная работа. Ты берёшь конкретного юзера «Вася Пупкин» и говоришь: «Вот этому файлу Вася имеет право на запись, а Петя — только на чтение». Гибко, но если юзеров овердохуища — админить это пиздец как неудобно.

  3. ABAC (Атрибутный доступ) — это уже для параноиков и гиков. Тут доступ решается по куче признаков: «Вася может редактировать документ, если он его автор, И сейчас рабочий день, И документ не помечен как секретный». Мощно, но сложно, блядь.

На практике после того, как ты аутентифицировался (ввёл логин-пароль), сервер тебе выдает JWT-токен — этакую цифровую бумажку, где написано, кто ты и какие у тебя права (роль). И дальше с этой бумажкой ты ходишь.

Вот, смотри, как это может выглядеть в коде на Flask. Делаем декоратор, который проверяет роль из токена:

from functools import wraps
from flask import request, jsonify
import jwt

# Предполагается, что токен содержит payload вида {'user': 'test', 'role': 'admin'}
SECRET_KEY = 'your-secret-key'

def role_required(role_name):
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            token = request.headers.get('Authorization')
            if not token:
                return jsonify({'message': 'Токен отсутствует'}), 401
            try:
                # Убираем 'Bearer '
                token = token.split()[1]
                payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
                # Проверяем наличие нужной роли
                if payload.get('role') != role_name:
                    return jsonify({'message': 'Недостаточно прав'}), 403
            except (jwt.ExpiredSignatureError, jwt.InvalidTokenError):
                return jsonify({'message': 'Невалидный токен'}), 401
            return f(*args, **kwargs)
        return decorated_function
    return decorator

@app.route('/admin/dashboard')
@role_required('admin')
def admin_dashboard():
    return 'Добро пожаловать в панель администратора!'

Видишь? Функция admin_dashboard обернута в @role_required('admin'). Если в твоём токене роль не admin — получишь ошибку 403 (Forbidden), то есть «Иди нахуй, Вася, тебе сюда нельзя». А если токен кривой или просроченный — будет 401 (Unauthorized), то есть «А ты вообще кто такой? Давай, до свидания».

Конечно, в больших фреймворках типа Django REST Framework или FastAPI это всё уже встроено — там свои классы пермишенов и зависимости. Но суть, блядь, одна: сначала узнай, кто ты, а потом проверь, можно ли тебе то, что ты хочешь. Всё просто, как три копейки!