# Нет доступа к форме или ошибка авторизации — Решение проблем

Runbook помогает разобрать обращения, когда пользователь не может открыть форму задачи или получает ошибку авторизации. Здесь собраны признаки инцидента, логика проверки доступа, чек-лист диагностики и SQL-запросы для быстрой проверки прав. Для инженеров поддержки и администраторов.

## 1. Когда использовать и сопоставление симптомов

Сценарий подходит, если есть один из следующих признаков инцидента:

1. Пользователь видит сообщение об отсутствии доступа — у категории с заданным «Названием сущности» оно называет её объект (`Нет доступа к кейсу`), без названия — прежнее `Нет доступа к задаче`, — или переходит на `/error/403`.
2. Открытие задачи по ID не работает, хотя задача существует.
3. Запросы к data source/форме возвращают `403 Forbidden`.
4. Есть жалобы на «ошибка авторизации» после логина/refresh токена.

Сопоставьте симптом с наиболее вероятной причиной и тем, что проверить в первую очередь:

| Симптом | Вероятная причина | Что проверить первым |
|---|---|---|
| После логина сразу 401/403 | недействительный access/refresh-токен, истекла сессия | `auth/token-v2`, `auth/token/refresh`, `auth/info` |
| Сообщение об отсутствии доступа при прямом открытии ID | задача есть, но `CheckTaskAccess=false` | `tasks/check-exist-and-access/{taskId}` |
| Изменяющий запрос отвечает `403` с кодом `CSRF_VALIDATION_FAILED` | включён строгий режим защиты от межсайтовой подделки, а метка у клиента устарела или запрос идёт не с доверенного адреса | `AuthCsrfProtectionMode` и `AuthCsrfTrustedOrigins`; журнал сервера по маршруту и причине отказа |
| Интерфейс «работает после F5», а до перезагрузки изменяющие запросы отклоняются | устаревшая метка защиты: клиент не обновил её | то же; проверить, что веб-клиент на сборке с повтором запроса |
| Вошедшего пользователя выбрасывает на вход, хотя вход был | истёк или отозван серверный сеанс; при смене пароля — ожидаемое поведение | список активных сеансов пользователя, журнал событий сеансов |
| Только часть пользователей не открывает задачу | role/subscriber различия | `UserTaskPermissions`, подписка на задачу |
| Доступ к задаче есть, но source возвращает 403 | нет прав на конкретный data source | endpoint source + серверный `AccessDeniedException` |
| Через замещение доступ пропал на конкретных задачах | задача конфиденциальная | признак confidential + проверка access без замещения |

## 2. Как устроена проверка доступа

### 2.1 Контур аутентификации и проверка доступа к задаче

Последовательность запросов при входе и проверке сессии:

1. SPA получает токен через `POST /api/auth/token-v2`.
2. Обновление сессии: `POST /api/auth/token/refresh`.
3. Проверка текущей сессии: `GET /api/auth/info`.
4. Глобально `403` перехватывается интерсептором и обычно ведёт на `/error/403` (кроме URL из списка исключений).

Перед открытием формы фронтенд проверяет доступ к задаче:

1. SPA вызывает `GET /api/tasks/check-exist-and-access/{taskId}`.
2. Сервер возвращает:
   - `IsTaskExists`,
   - `IsUserHasAccess`,
   - `TaskShortInfo`.
3. При `IsTaskExists = true` и `IsUserHasAccess = false` в `TaskShortInfo` приходят только идентификаторы — номер задачи, категория, её тип, признак пространства и владелец: ни имени владельца, ни исполнителей, ни текста, статуса и приоритета в ответе нет. Фронтенд показывает сообщение об отсутствии доступа, называя объект по категории и номеру; персональные данные автора задачи при отказе не отдаются. Первая часть сообщения называет объект по категории:

   - если «Название сущности» не задано — прежнее «Нет доступа к задаче»;
   - для однословного названия на русском — дательный падеж со строчной буквы («Нет доступа к кейсу»);
   - для составного названия из двух и более слов — неизменяемая форма перед отказом («Карточка клиента. Нет доступа», на экранах с номером объекта — «Карточка клиента №12345. Нет доступа»).

   Правило построения фразы живёт в хелпере `no-access-message.ts` (`getNoAccessMessage`): неизменяемый шаблон берётся, когда название состоит из нескольких слов и дательной формы нет.

### 2.2 Как рассчитывается доступ к задаче и data source

Доступ к задаче проверяется по следующей логике:

1. Проверяется существование задачи.
2. Системный робот (`SystemRobot`) — доступ всегда есть.
3. Уволенный пользователь (`IsFired`) — доступа нет.
4. Для административных операций (удаление задачи, доступ к data source):
   - либо полный доступ (super-admin),
   - либо право на изменение задачи (Set).
5. Для обычного открытия задачи:
   - подписка на задачу даёт доступ,
   - для конфиденциальной задачи доступ через замещение не расширяется,
   - затем проверка через функции БД `fn_UserTaskPermissions` / `fn_CheckUserTaskPermissions`.

Запрос к data source при отказе в доступе возвращает `403`.
Это отдельный уровень прав: пользователь может иметь базовый доступ к задаче, но не иметь доступа к конкретному source или действию.

## 3. Что смотреть при разборе (чек-лист)

При разборе инцидента пройдите по шагам:

1. Зафиксировать: `userId`, `taskId`, URL экрана, время, текст ошибки.
2. Проверить аутентификацию:
   - успешен ли `auth/token-v2` или `auth/token/refresh`,
   - возвращает ли `auth/info` корректного пользователя.
3. Проверить `tasks/check-exist-and-access/{taskId}`:
   - `IsTaskExists = false` — это не доступ, а отсутствующая или некорректная задача,
   - `IsTaskExists = true`, `IsUserHasAccess = false` — чистый случай прав.
4. Если это 403 от data source:
   - зафиксировать конкретный endpoint source,
   - разделить проблему прав задачи и прав source.
5. Проверить, не уволен ли пользователь, нет ли эффекта перевоплощения (impersonation).
6. Проверить, не конфиденциальная ли задача (для таких задач замещение ограничено).
7. Проверить факт подписки пользователя на задачу.
8. Проверить `fn_UserTaskPermissions`/`fn_CheckUserTaskPermissions` по задаче.

## 4. SQL и материалы для поддержки

Следующие SQL-запросы позволяют проверить права доступа пользователя к задаче напрямую в базе данных: наличие пользователя, доступность задачи через денормализованный контур прав, проверку через функцию и факт подписки.

```sql
-- Входные параметры
-- @user_id int
-- @task_id int

-- Базовая информация по пользователю
select
        u.UserID,
        u.IsFired
from dbo.Users u
where u.UserID = @user_id;

-- Базовая информация по задаче
select
        t.TaskID,
        t.SubcatID,
        t.UserID as OwnerUserID
from dbo.Tasks t
where t.TaskID = @task_id;

-- Видит ли пользователь задачу через денормализованный контур прав
select top (1)
        utp.TaskID,
        utp.UserID
from dbo.UserTaskPermissions utp
where utp.TaskID = @task_id and
      utp.UserID = @user_id;

-- Проверка права через функцию (MS SQL путь)
select
        p.TaskID
from dbo.fn_CheckUserTaskPermissions(
        @task_id,
        @user_id,
        (
            select t.SubcatID
            from dbo.Tasks t
            where t.TaskID = @task_id
        )
) p;

-- Проверка подписки на задачу
select top (20)
        ms.TaskID,
        ms.UserID,
        ms.DateAdd
from dbo.MailSubscribers ms
where ms.TaskID = @task_id and
      ms.UserID = @user_id
order by
        ms.DateAdd desc;
```

Если разобраться не удалось, соберите и приложите к обращению в поддержку 1Ф:

1. `userId`, `taskId`, URL и шаги воспроизведения.
2. Ответы `auth/info` и `tasks/check-exist-and-access/{taskId}`.
3. Текст или скриншот `403` (если от data source — какой именно endpoint).
4. SQL-снимок из блока выше.
5. Было ли перевоплощение (impersonate) и повторяется ли проблема без него.
