← Назад к вопросам

Через какую концепцию реализуется авторизация

1.0 Junior🔥 61 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Концепции реализации авторизации

Авторизация — это процесс проверки прав доступа пользователя к ресурсам. Это отличается от аутентификации (проверка личности пользователя). Авторизация реализуется через несколько ключевых концепций.

1. RBAC (Role-Based Access Control) — Контроль доступа на основе ролей

Это самая популярная концепция. Пользователю присваивается роль, а роль определяет, что пользователь может делать.

from enum import Enum
from typing import Set
from dataclasses import dataclass

class Role(Enum):
    ADMIN = "admin"
    MODERATOR = "moderator"
    USER = "user"
    GUEST = "guest"

@dataclass
class User:
    id: int
    email: str
    roles: Set[Role]

# Определяем права для каждой роли
ROLE_PERMISSIONS = {
    Role.ADMIN: {"create_user", "delete_user", "view_logs", "edit_post"},
    Role.MODERATOR: {"edit_post", "delete_comment", "ban_user"},
    Role.USER: {"create_post", "create_comment", "edit_own_post"},
    Role.GUEST: {"read_post", "read_comment"},
}

def has_permission(user: User, permission: str) -> bool:
    """Проверяет есть ли у пользователя нужное разрешение."""
    for role in user.roles:
        if permission in ROLE_PERMISSIONS.get(role, set()):
            return True
    return False

# Пример использования в API
from fastapi import FastAPI, Depends, HTTPException

app = FastAPI()

def require_permission(permission: str):
    async def check_permission(user: User = Depends(get_current_user)):
        if not has_permission(user, permission):
            raise HTTPException(status_code=403, detail="Forbidden")
        return user
    return check_permission

@app.post("/api/users")
async def create_user(user: User = Depends(require_permission("create_user"))):
    # Только пользователи с правом create_user могут создавать юзеров
    return {"status": "user created"}

2. PBAC (Permission-Based Access Control) — Контроль доступа на основе разрешений

Более гранулярная концепция. Вместо ролей проверяются конкретные разрешения (permissions).

from dataclasses import dataclass
from typing import Set

@dataclass
class Permission:
    name: str
    description: str

@dataclass
class User:
    id: int
    email: str
    permissions: Set[Permission]

# Разрешения (более детальные)
PERMISSION_CREATE_POST = Permission("create_post", "Может создавать посты")
PERMISSION_DELETE_POST = Permission("delete_post", "Может удалять посты")
PERMISSION_EDIT_OTHER_POST = Permission("edit_other_post", "Может редактировать чужие посты")

def check_permission(user: User, required_permission: Permission) -> bool:
    return required_permission in user.permissions

# Удобнее для гибких систем разрешений
class PermissionBasedAccessControl:
    def __init__(self, user: User):
        self.user = user
    
    def can(self, permission: Permission) -> bool:
        return permission in self.user.permissions
    
    def can_delete_post(self, post_author_id: int) -> bool:
        # Может удалять свои посты ИЛИ иметь разрешение на удаление
        if post_author_id == self.user.id:
            return True
        return self.check_permission(self.user, PERMISSION_DELETE_POST)

3. ABAC (Attribute-Based Access Control) — Контроль доступа на основе атрибутов

Самая гибкая концепция. Доступ зависит от атрибутов пользователя, ресурса, окружения.

from dataclasses import dataclass
from typing import Any, Dict
from datetime import datetime

@dataclass
class AccessContext:
    user_id: int
    user_department: str
    user_level: int
    resource_type: str
    resource_owner_id: int
    request_time: datetime
    request_ip: str

def check_access_abac(context: AccessContext) -> bool:
    """
    Проверяет доступ на основе атрибутов.
    Правила очень гибкие.
    """
    # Правило 1: Администраторы (level > 100) могут всё
    if context.user_level > 100:
        return True
    
    # Правило 2: Владелец ресурса может редактировать его
    if context.user_id == context.resource_owner_id:
        return True
    
    # Правило 3: Менеджеры (level >= 50) могут работать с ресурсами своего отдела
    if context.user_level >= 50 and context.resource_type == "department_report":
        # Проверяем БД для связи
        return True
    
    # Правило 4: Доступ только в рабочие часы (9-17)
    if 9 <= context.request_time.hour < 17:
        if context.user_level >= 30:
            return True
    
    # Правило 5: Доступ из офиса
    office_ips = ["192.168.1.0/24", "10.0.0.0/8"]
    if context.request_ip in office_ips:
        return True
    
    return False

# Использование с FastAPI
from fastapi import FastAPI, Request

app = FastAPI()

@app.get("/api/resource/{resource_id}")
async def get_resource(resource_id: int, request: Request):
    user = get_current_user()  # аутентификация
    
    context = AccessContext(
        user_id=user.id,
        user_department=user.department,
        user_level=user.access_level,
        resource_type="document",
        resource_owner_id=get_resource_owner(resource_id),
        request_time=datetime.now(),
        request_ip=request.client.host,
    )
    
    if not check_access_abac(context):
        raise HTTPException(status_code=403, detail="Forbidden")
    
    return get_resource(resource_id)

4. JWT (JSON Web Tokens) — Токены для авторизации

Механизм передачи прав в API.

from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import HTTPBearer, HTTPAuthCredentials
import jwt
from datetime import datetime, timedelta

SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"

# Создание токена
def create_access_token(user_id: int, roles: list, expires_in_hours=24):
    payload = {
        "user_id": user_id,
        "roles": roles,
        "exp": datetime.utcnow() + timedelta(hours=expires_in_hours),
        "iat": datetime.utcnow(),
    }
    token = jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
    return token

# Проверка токена
def verify_access_token(token: str):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        user_id = payload.get("user_id")
        roles = payload.get("roles", [])
        return {"user_id": user_id, "roles": roles}
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token expired")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=401, detail="Invalid token")

# Использование в FastAPI
security = HTTPBearer()

app = FastAPI()

@app.post("/api/login")
async def login(email: str, password: str):
    # Проверяем пароль (аутентификация)
    user = authenticate_user(email, password)
    if not user:
        raise HTTPException(status_code=401, detail="Invalid credentials")
    
    # Создаём токен (авторизация)
    token = create_access_token(user.id, user.roles)
    return {"access_token": token, "token_type": "bearer"}

@app.get("/api/protected")
async def protected_route(credentials: HTTPAuthCredentials = Depends(security)):
    payload = verify_access_token(credentials.credentials)
    
    # Теперь знаем user_id и roles
    user_id = payload["user_id"]
    roles = payload["roles"]
    
    return {"user_id": user_id, "roles": roles}

5. OAuth 2.0 — Стандарт для делегированного доступа

Используется для разрешения доступа к ресурсам от имени пользователя.

from fastapi import FastAPI
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel

app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

class Token(BaseModel):
    access_token: str
    token_type: str

class TokenData(BaseModel):
    user_id: int
    scopes: list

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    # Проверяем учётные данные
    user = authenticate_user(form_data.username, form_data.password)
    if not user:
        raise HTTPException(status_code=401, detail="Invalid credentials")
    
    # Возвращаем токен доступа
    access_token = create_access_token(
        data={"user_id": user.id, "scopes": user.scopes}
    )
    return {"access_token": access_token, "token_type": "bearer"}

@app.get("/users/me")
async def read_users_me(token: str = Depends(oauth2_scheme)):
    user = verify_token(token)
    return {"user_id": user.user_id, "scopes": user.scopes}

6. ACL (Access Control List) — Списки контроля доступа

Для специфичных прав на конкретные объекты.

from typing import Dict, Set

class ACL:
    def __init__(self):
        # resource_id -> {user_id -> permissions}
        self.permissions: Dict[int, Dict[int, Set[str]]] = {}
    
    def grant(self, resource_id: int, user_id: int, permission: str):
        if resource_id not in self.permissions:
            self.permissions[resource_id] = {}
        
        if user_id not in self.permissions[resource_id]:
            self.permissions[resource_id][user_id] = set()
        
        self.permissions[resource_id][user_id].add(permission)
    
    def revoke(self, resource_id: int, user_id: int, permission: str):
        if resource_id in self.permissions:
            if user_id in self.permissions[resource_id]:
                self.permissions[resource_id][user_id].discard(permission)
    
    def check(self, resource_id: int, user_id: int, permission: str) -> bool:
        return (
            resource_id in self.permissions
            and user_id in self.permissions[resource_id]
            and permission in self.permissions[resource_id][user_id]
        )

# Использование
acl = ACL()
acl.grant(resource_id=1, user_id=123, permission="read")
acl.grant(resource_id=1, user_id=123, permission="edit")

# Проверка
if acl.check(resource_id=1, user_id=123, permission="edit"):
    print("Доступ разрешён")

Сравнение концепций

КонцепцияСложностьГибкостьМасштабируемость
RBACНизкаяСредняяХорошо
PBACСредняяВысокаяХорошо
ABACВысокаяОченьОтлично
ACLСредняяСредняяХорошо

Практическая реализация в реальном проекте

# Часто используют комбинацию подходов
from functools import wraps

class AuthorizationService:
    def __init__(self):
        self.role_permissions = {}  # RBAC
        self.acl = ACL()  # ACL
    
    def check_access(self, user: User, resource_id: int, action: str) -> bool:
        # Сначала проверяем RBAC
        for role in user.roles:
            if self._has_role_permission(role, action):
                # Затем проверяем ACL
                if self.acl.check(resource_id, user.id, action):
                    return True
        return False

def require_access(action: str):
    def decorator(func):
        @wraps(func)
        async def wrapper(resource_id: int, user: User = Depends(get_current_user)):
            auth_service = AuthorizationService()
            if not auth_service.check_access(user, resource_id, action):
                raise HTTPException(status_code=403, detail="Forbidden")
            return await func(resource_id, user)
        return wrapper
    return decorator

Заключение

Авторизация реализуется через разные концепции:

  • RBAC — когда роли = разрешения
  • PBAC — когда нужна гибкость
  • ABAC — для сложных систем
  • ACL — для специфичных прав на объекты
  • JWT/OAuth — для безопасной передачи прав

Выбор зависит от требований вашей системы.

Через какую концепцию реализуется авторизация | PrepBro