Документ фиксирует текущую модель доступа в PTKnow. Его задача — дать однозначный ответ, кто и к каким точкам API имеет доступ, чтобы это можно было сверять с SecurityConfig, контроллерами, сервисами и слоем политик.
ANONYMOUS- пользователь не вошёл в системуGUEST- пользователь вошёл в систему, но ещё не подтверждён колледжемSTUDENT- подтверждённый студентTEACHER- преподавательADMIN- администратор платформы
OWNER и EDITOR не являются глобальными ролями.
OWNER - контекстное право владения конкретным ресурсом:
OWNER(profile)=profile.userId == currentUser.idOWNER(course)=course.ownerId == currentUser.idOWNER(lesson)=lesson.ownerId == currentUser.idOWNER(file)= файл принадлежит профилю, курсу или уроку, владельцем которого является текущий пользователь
Правила:
- владение ресурсом не должно проверяться только в контроллере
- владение ресурсом должно подтверждаться в сервисе или слое политик
ADMINимеет доступ ко всем ресурсам независимо от владения
EDITOR — контекстное право редактирования конкретного курса:
EDITOR(course)= пользователь добавлен в список редакторов курса
Правила:
EDITORне является глобальной ролью- права редактора должны проверяться в сервисе или слое политик
ADMINимеет доступ к изменению всех ресурсов независимо от статуса редактора
Целевая модель ролей:
ANONYMOUS -> GUESTпосле регистрацииGUEST -> STUDENTпосле подтверждения колледжемGUEST -> TEACHERпосле подтверждения колледжем или назначения администраторомSTUDENT -> GUESTиTEACHER -> GUESTпри отзыве подтвержденияADMINназначается только вручную
В текущей реализации уже есть:
- административное изменение роли
- журналирование изменения роли
- запрет на самоназначение привилегированной роли
401 Unauthorized— пользователь не вошёл в систему или токен недействителен403 Forbidden— пользователь вошёл в систему, но не имеет права на действие404 Not Found— ресурс не существует
Принципы:
- ошибки доступа не должны превращаться в
500 - внутренние ошибки не должны маскироваться под
401
enrollment — запись пользователя на курс.
ENROLLED — пользователь записан на конкретный курс.
Правила:
- проверка записи на курс выполняется в сервисе
- запись на курс не заменяет владение, права редактора и права администратора, а дополняет их
- каждая точка API, изменяющая состояние, обязана иметь явное правило доступа
- каждая проверка владения ресурсом должна находиться в сервисе или слое политик
ADMINимеет полный доступ ко всем ресурсам- access- и refresh-токены не должны логироваться целиком
- refresh-токены в базе хранятся только в виде хэша
- в рабочем окружении refresh-cookie должны быть
HttpOnlyиSecure - правила в коде должны соответствовать этому документу
Сделано— правило реализовано и соответствует текущему кодуНе сделано— правило описано, но ещё не реализованоНет в доменной модели— для реализации правила не хватает сущности, связи или части модели
POST /api/v0/auth/register—ANONYMOUS—СделаноPOST /api/v0/auth/login—ANONYMOUS—СделаноPOST /api/v0/auth/logout— любой пользователь, вошедший в систему:GUEST,STUDENT,TEACHER,ADMIN—СделаноPOST /api/v0/token/refresh—ANONYMOUSили пользователь, вошедший в систему, при наличии действительного refresh-токена —Сделано
GET /api/v0/profile—GUEST,STUDENT,TEACHER,ADMIN—СделаноGET /api/v0/profile/me—OWNER(profile)—СделаноGET /api/v0/profile/search—ANONYMOUS,GUEST,STUDENT,TEACHER,ADMIN—СделаноGET /api/v0/profile/{handle}—ANONYMOUS,GUEST,STUDENT,TEACHER,ADMIN—СделаноGET /api/v0/profile/id/{userId}—ADMIN,OWNER(profile)—СделаноPATCH /api/v0/profile—OWNER(profile)—СделаноPUT /api/v0/profile—OWNER(profile)—СделаноPOST /api/v0/profile/avatar—OWNER(profile)—СделаноDELETE /api/v0/profile/avatar—OWNER(profile)—Сделано
GET /api/v0/files/{id}— доступ зависит отfileVisibilityвложения и видимости родительского ресурса —СделаноPUBLIC—ANONYMOUS,GUEST,STUDENT,TEACHER,ADMIN—СделаноENROLLED—ENROLLED,OWNER(course|lesson),EDITOR(course),ADMIN; анонимный доступ возможен только для опубликованного родительского курса и только если это допускает общая политика чтения —СделаноPRIVATE—OWNER(profile|course|lesson),ADMIN—СделаноGET /api/v0/files/{id}/meta—OWNER(file),ADMIN—СделаноDELETE /api/v0/files/{id}—OWNER(file),ADMIN—Сделано
GET /api/v0/course—ANONYMOUS,GUEST,STUDENT,TEACHER,ADMIN; для анонимных и обычных пользователей доступны только опубликованные курсы, а владельцы и редакторы видят свои черновики и архивные курсы через правила сервиса —СделаноPOST /api/v0/course—TEACHER,ADMIN—СделаноPATCH /api/v0/course/{id}—OWNER(course),ADMIN—СделаноPUT /api/v0/course/{id}—OWNER(course),ADMIN—СделаноGET /api/v0/course/id/{id}—ANONYMOUSдляPUBLISHED,ENROLLED,OWNER(course),EDITOR(course),ADMIN;DRAFTиARCHIVEDнедоступны пользователям без управляющих прав —СделаноGET /api/v0/course/handle/{handle}— те же правила, что и дляGET /api/v0/course/id/{id}—СделаноPOST /api/v0/course/{id}/preview—OWNER(course),EDITOR(course),ADMIN; видимость preview синхронизируется с состоянием курса —СделаноDELETE /api/v0/course/{id}—OWNER(course),ADMIN—СделаноPOST /api/v0/course/{id}/editors/{userId}—OWNER(course),ADMIN—СделаноDELETE /api/v0/course/{id}/editors/{userId}—OWNER(course),ADMIN—СделаноPOST /api/v0/course/{id}/publish—OWNER(course),ADMIN—СделаноPOST /api/v0/course/{id}/archive—OWNER(course),ADMIN—СделаноPOST /api/v0/course/{id}/enroll—GUEST,STUDENT; дополнительно применяются ограничения записи на курс —СделаноDELETE /api/v0/course/{id}/enroll— пользователь может отменить только собственную запись на курс —СделаноGET /api/v0/course/{id}/members—OWNER(course),EDITOR(course),ENROLLED,ADMIN—СделаноGET /api/v0/course/{id}/students—OWNER(course),ADMIN—СделаноGET /api/v0/course/{id}/teachers—OWNER(course),ADMIN—СделаноPOST /api/v0/course/{id}/teachers—OWNER(course),ADMIN—СделаноDELETE /api/v0/course/{id}/teachers/{teacherId}—OWNER(course),ADMIN—Сделано
contentMd является частью ресурса lesson и подчиняется тем же правилам доступа, что и сам урок.
POST /api/v0/lessons/{courseId}—OWNER(course),EDITOR(course),ADMIN—СделаноGET /api/v0/lessons/{lessonId}—ANONYMOUSдля уроков опубликованного курса,ENROLLED,OWNER(course),EDITOR(course),ADMIN—СделаноGET /api/v0/lessons/course/{courseId}—ANONYMOUSдля опубликованного курса,ENROLLED,OWNER(course),EDITOR(course),ADMIN—СделаноPATCH /api/v0/lessons/{lessonId}—OWNER(lesson),ADMIN—СделаноPUT /api/v0/lessons/{lessonId}—OWNER(lesson),ADMIN—СделаноPATCH /api/v0/lessons/{lessonId}/state—OWNER(lesson),ADMIN—СделаноDELETE /api/v0/lessons/{lessonId}—OWNER(lesson),OWNER(course),ADMIN—СделаноPOST /api/v0/lessons/{lessonId}/materials—OWNER(lesson),ADMIN—СделаноDELETE /api/v0/lessons/{lessonId}/materials/{fileId}—OWNER(lesson),ADMIN—Сделано
GET /api/v0/users—ADMIN—СделаноGET /api/v0/users/{id}—ADMIN—СделаноPATCH /api/v0/users/{id}/role—ADMIN; самоназначение привилегированной роли запрещено —СделаноPATCH /api/v0/users/{id}/status—ADMIN; запрет на блокировку самого себя реализован —Сделано