Серия «Записки вкатуна»

3

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT)

Термины в статье:

  1. Эндпоинт

  2. Аутентификация, Регистрация, JWT, Access, Refresh

К стеку добавился:

  • Vue.js

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

Дописываю API

Потратив 2 ночи (и немного терпения), я наконец завершил реализацию всех эндпоинтов! В какой-то момент это очень наскучило, но я все равно продолжал писать их.

Как выглядят эндпоинты в этой статье - Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса.

Архитектура папок теперь выглядит вот так:

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

Всего реализовано 38 эндпоинтов , и это еще не конец — их количество будет расти! Последний из них ощущался как будто я пробежал марафон.


Разработка дизайна 🎨

Но как делать веб без дизайна? Верно, никак! 🤔
Зайдя в Figma и подсмотрев интерфейс GitHub'а , я накидал ориентировочный дизайн страниц регистрации и входа.

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост
Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

Верстка 🖥️

Верстка — это немного рутинное занятие, но результат того стоит!
Могу сказать, что получилось почти идентично дизайну.

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

Frontend с Vue.js

Почему Vue.js ? Просто такие условия 🙃. Если бы выбор был за мной, я бы взял React .

Добавлю в решение новый проект Веб-приложение ASP.NET Core (MVC) . Стандартный шаблон создаст такие папки:

  • wwwroot
    Это корневая папка для статических файлов, которые будут доступны напрямую через браузер.

  • Controllers
    Папка содержит классы контроллеров, которые управляют маршрутизацией.

  • Models
    Папка содержит модели данных, которые представляют сущности приложения.

  • Views
    Папка содержит представления — файлы, которые отвечают за отображение HTML-страниц пользователю.

В папку wwwroot/lib добавлю клиентскую библиотеку Vue.js .

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

Создам новый контроллер для страниц аутентификации.

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

В папке Views есть еще 2 папки:

  • Home

  • Shared

В папку Shared добавлю новый шаблон страницы Razor с названием _LoginLayout для страниц аутентификации.

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

Создам папку Auth, добавив туда пустую страницу Razor с названием _ViewStart. Этот файл указывает какой шаблон будут использовать страницы.

@{

Layout = "_LoginLayout";

}

Теперь закину в wwwroot/css свой файл со стилем, который наверстал.


Логика фронтенда 🧠

Начну со страницы входа, добавив HTML-разметку, которую наверстал.

Снизу файла напишу блок скриптов:

@Section scripts {

<script src="~/lib/vue/vue.global.js"></script>

<script>

...тут будут все скрипты...

</script>

}

Пример запроса на бэкенд:

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

На скрине показан метод ассинхронный метод login(), в нем реализована отправка запроса на эндпоинт /auth/login, если запрос проходит успешно, я записываю Access-токен в локальное хранилище и перенаправляю пользователя на страницу по адресу /home. В противном случае я показываю ошибку пользователю.

В ответе сервера я получаю Access и Refresh токены.

  • Access-токен записываю в локальное хранилище.

  • Refresh-токен храню в Http-only куках для большей безопасности 🛡️.

Пример записи куки на сервере:

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

Здесь я записал новую куку с под названием refreshToken, и значением, равным Refresh-токену.

Вообще для чего мне Refresh-токен, если есть Access? Все очень просто, у Access-токена срок жизни 15 минут, поэтому через 15 минут его необходимо будет сгенерировать заново. Для этого как раз и понадобится Refresh-токен.

По истечению Access-токена я буду посылать на сервер запрос со своими куками. Сервер прочитает Refresh-токен из них и, если он валидный, вернет новый Access-токен.

Как это реализовано со стороны сервера:

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

Со стороны клиента:

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

При загрузке страницы сразу же срабатывает метод checkRefreshToken, далее отправляется запрос на /auth/refresh. Если сервер возвращает положительный ответ, записываю новый Access в локальное хранилище и продолжаю пользоваться сервисом.

Тестирование 🧪

Запущу бэкенд и фронтенд.

После запуска я сразу попадаю на страницу входа.

Войду в аккаунт, который я создвал еще на начальных этапах.

Если сейчас обратиться по адресу /home, меня перекинет назад на страницу авторизации.

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

Попробую сначала ввести неправильный пароль.

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

Теперь введу правильный пароль. Все сработало! Я попал на домашнюю страницу.

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

Зайдя в консоль разработчика, можно посмотреть локальное хранилище и найти там Access-токен.

Создаю онлайн-сервис для чтения книг. День 6-9. CRUD, Дизайн+Верстка, Frontend(JWT) Разработка, Программирование, Aspnet, Frontend, Backend, Длиннопост

Теперь я могу пользоваться сервисом, отправляя запросы на эндпоинты, передавая данный токен в заголовке.

Показать полностью 15
2

Создаю онлайн-сервис для чтения книг. День 5. Подтверждение почты

🎁 Бонусная статья.

Создаю онлайн-сервис для чтения книг. День 5. Подтверждение почты Программирование, Электронная почта, Aspnet, Длиннопост

🛠️ Добавлю новую таблицу в БД

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

  • id: уникальный идентификатор

  • code: сгенерированный код

  • email: почта, на которую пришел код

  • expires_in: дата и время истечения кода

Создаю онлайн-сервис для чтения книг. День 5. Подтверждение почты Программирование, Электронная почта, Aspnet, Длиннопост

🖥️ Создам интерфейс и реализую его

Опишу методы работы с этой базой данных через интерфейс.

Создаю онлайн-сервис для чтения книг. День 5. Подтверждение почты Программирование, Электронная почта, Aspnet, Длиннопост

🔐 Интерфейс сервиса аутентификации

В интерфейс добавлю логику для отправки кода на почту.

Создаю онлайн-сервис для чтения книг. День 5. Подтверждение почты Программирование, Электронная почта, Aspnet, Длиннопост

Отправляться будет шестизначный код. Генерация кода выглядит так:

Создаю онлайн-сервис для чтения книг. День 5. Подтверждение почты Программирование, Электронная почта, Aspnet, Длиннопост

📧 Настройка почты

Теперь зайду в mail.ru и создам новую почту. Перейду в настройки безопасности и выберу пункт "Пароли для внешних приложений" . Создам новое внешнее приложение и получу для него пароль. Запишу его себе куда-нибудь.


📦 Подключаю библиотеку System.Net.Mail

Для отправки сообщений необходимо подключить библиотеку System.Net.Mail. Она поможет настроить SMTP-клиент и отправить письмо.


🎯 Генерация кода и запись в БД

1. Параметры SMTP-сервера

Эти переменные необходимы для настройки подключения к SMTP-серверу, который будет отправлять письмо.

smtpServer

smtpPort

  • Описание : Порт, используемый для подключения к SMTP-серверу. Обычно это:

    • 587 (для TLS/STARTTLS)

    • 465 (для SSL)

  • Пример : 587 для Gmail или Mail.ru.

smtpUsername

  • Описание : Логин (обычно email), который используется для аутентификации на SMTP-сервере.

smtpPassword

  • Описание : Пароль для аутентификации на SMTP-сервере. В моем случае я вписал пароль, который недавно получил от mail.ru.


2. Параметры объекта MailMessage

Класс MailMessage используется для создания самого письма. Вот его основные параметры:

IsBodyHtml = true

  • Описание : Этот флаг указывает, что тело письма содержит HTML-разметку. Если установлено значение false, то тело письма будет обрабатываться как простой текст.

From

  • Описание : Указывает адрес отправителя. Это поле должно быть заполнено объектом типа MailAddress.

To

  • Описание : Указывает адрес получателя. Можно добавить несколько адресов с помощью метода message.To.Add().

Subject

  • Описание : Тема письма, которая отображается в заголовке сообщения.

Body

  • Описание : Тело письма. Если IsBodyHtml = true, то здесь можно использовать HTML-разметку. В противном случае это будет простой текст. В моем случае я сверстал небольшую форму, записал её в отдельную переменную класса Constaints.

Создаю онлайн-сервис для чтения книг. День 5. Подтверждение почты Программирование, Электронная почта, Aspnet, Длиннопост

🌐 Добавляю эндпоинт

Создам эндпоинт, который будет отвечать за отправку сообщения. Например:

Создаю онлайн-сервис для чтения книг. День 5. Подтверждение почты Программирование, Электронная почта, Aspnet, Длиннопост

🧪 Тестирую!

Запускаю сервер и тестирую функционал:

  • Ввожу адрес электронной почты, на который хочу отправить сообщение. 📝

Создаю онлайн-сервис для чтения книг. День 5. Подтверждение почты Программирование, Электронная почта, Aspnet, Длиннопост
  • Нажимаю "Выполнить". ✅

И... Письмо пришло! 🎉

Создаю онлайн-сервис для чтения книг. День 5. Подтверждение почты Программирование, Электронная почта, Aspnet, Длиннопост

🗄️ Проверяю БД

Убеждаюсь, что запись добавлена в базу данных. Все отлично работает! ✅

Создаю онлайн-сервис для чтения книг. День 5. Подтверждение почты Программирование, Электронная почта, Aspnet, Длиннопост

🎉 Итог

Теперь пользователи могут подтвердить свою почту с помощью шестизначного кода.

Показать полностью 9
1

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access

Термины в статье:

  1. CRUD, крудошлеп

  2. Endpoint

  3. JWT

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

🚀 Изменения в БД:

Для поддержки доступа к сайту с нескольких устройств (веб, десктоп, мобильное приложение) в таблицу UserSessions были добавлены следующие столбцы:

  • device_type : Тип устройства (web, desktop, mobile)

  • created_at : Дата создания сессии

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

🛠️ Изменения в коде:

1. Удаление флага bool Flag

Ранее в ответах сервера использовался флаг bool Flag для обозначения успешности операции. Теперь обработка ошибок выполняется через блоки try-catch. Это делает код более читаемым и устойчивым к ошибкам.

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост
Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

🐣 Реализация JWT-токенов

  1. В файл конфигурации appsettings.json добавлен новый раздел JwtSection, содержащий секретный ключ и время жизни токена:

  2. Для удобства работы с JWT был создан вспомогательный класс, который хранит данные из раздела JwtSection.

  3. В Program.cs этот класс подключается следующим образом:

    builder.Services.Configure<JwtSection>(builder.Configuration.GetSection("JwtSection"));

  4. Был создан интерфейс, описывающий логику работы с базой данных для управления сессиями.

  5. Реализую данный интерфейс. 💻


🔑 Генерация токенов:

Для генерации refresh-токена используется метод, который создает случайную строку из 32 байт:

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

Для генерации access-токена необходимы данные о пользователе (claims), секретный ключ из appsettings.json и срок действия токена:

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

🔒 Метод SignIn:

В методе SignIn происходит следующее:

  1. Генерируются Access и Refresh токены.

  2. Проверяется наличие сессии в базе данных. Если сессия существует, обновляется Refresh-токен.

  3. Если сессия не найдена, создается новая запись в таблице UserSessions.

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

Обновление токенов 🔄

Если срок действия Access-токена истек, пользователь может получить новый токен, используя Refresh-токен. Для этого реализован метод RefreshToken:

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

Здесь происходят базовые проверки, во избежание ошибок. Далее генерируется новый Access-токен. Если срок Refresh-токена истек, то генерирую новый и отправляю его пользователю вместе с Access-токеном.


Защита эндпоинтов 🛡️

Для защиты эндпоинтов от неавторизованных пользователей была добавлена логика обработки Access-токенов:

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

Здесь из appsettings.json достаются все данные из ячейки JwtSection и помещаются в переменную config. Это позволяет централизованно управлять секретным ключом и временем жизни токена.

Далее добавляется аутентификация, указывая схему аутентификации (JwtBearer) в качестве параметра. Для этого используется метод AddJwtBearer, который как раз и будет валидировать токен. В нем указываются следующие проверки:

  • Срок жизни токена : Убедиться, что токен не истек. ⏳

  • Ключ шифрования : Проверить, что токен был подписан с использованием корректного секретного ключа. 🔑

В Program.cs регистрируется метод AddAuth:

builder.Services.AddAuth(builder.Configuration);

Также добавлены строки для использования аутентификации и авторизации

app.UseAuthentication();

app.UseAuthorization();

Теперь необходимо защитить Endpoint. Защищенные эндпоинты помечаются атрибутом [Authorize]:

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

Проверка работоспособности ▶️

Регистрация нового аккаунта 🆕

Регистрация проходит успешно, если данные пользователя уникальны.

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

Авторизация 🔑

После входа в систему пользователь получает Access и Refresh токены.

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост
Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

Проверка токена на jwt.io 🔍

На сайте jwt.io можно проверить содержимое Access-токена. В поле Payload видны все Claims.

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

Обращение к защищенному эндпоинту без токена 🚫

Получен статус-код 401, что означает "Доступ запрещен".

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост
Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

Обращение с токеном ✅

После добавления токена в заголовок Authorization запрос выполнен успешно (статус-код 200).

Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост
Создаю онлайн-сервис для чтения книг. День 5. JWT, Refresh, Access Программирование, Разработка, Длиннопост

Заключение 🎉

Все компоненты системы аутентификации и управления сессиями работают корректно. Далее буду крудошлепить остальную бизнес-логику по аналогии.

🥁 А темой для следующей статьи станет:

Подтверждение почты через отправку кода в письме

Показать полностью 17

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса

Термины в статье:

  1. DTO

  2. Endpoint

  3. JWT

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

Реализация обработки первого запроса 🚀

1. Добавление логов 📝

Логи пишутся практически при каждом действии пользователей, поэтому начну с их реализации в качестве примера.

  • Перейду в проект HelpLibrary и создам новый класс в папке DTOs .

  • Создам DTO для логов:

    DTO Logs

  • Теперь перейду в проект ServerLibrary и добавлю интерфейс ILogRepository для определения класса логов.

  • Реализую этот интерфейс, создав класс LogRepository в папке Implementations . Он содержит:

    • Поле _context, которое объявляется в конструкторе для контекста базы данных.

    • Реализацию метода WriteLogs, который записывает логи в базу данных.

💡 Важно: Такой шаблон будет использоваться для каждой таблицы базы данных.

Qwen2.5-Max1:29 am

Вот обновленная версия текста с добавлением стикеров для улучшения визуального восприятия и акцентирования внимания на ключевых моментах:


Реализация обработки первого запроса 🚀

1. Добавление логов 📝

Логи пишутся практически при каждом действии пользователей, поэтому начну с их реализации в качестве примера.

  • Перейду в проект HelpLibrary и создам новый класс в папке DTOs .

  • Создам DTO для логов:

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост
  • Теперь перейду в проект ServerLibrary и добавлю интерфейс ILogRepository для определения класса логов.

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост
  • Реализую этот интерфейс, создав класс LogRepository в папке Implementations . Он содержит:

    • Поле _context, которое объявляется в конструкторе для контекста базы данных.

    • Реализацию метода WriteLogs, который записывает логи в базу данных.

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

💡 Важно: Такой шаблон будет использоваться для каждой таблицы базы данных.


2. Логика работы с пользователями 👤

Создам DTO для регистрации и входа в аккаунт:

  • Для регистрации обязательными полями являются: логин , имя , email и пароль .

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост
  • Для входа в аккаунт необходимы: почта/логин и пароль .

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

Интерфейс репозитория 🔍

Определяю интерфейс репозитория для работы с базой данных. На данном этапе необходимо реализовать следующие методы:

  • Поиск пользователя по Id .

  • Поиск пользователя по никнейму .

  • Поиск пользователя по email .

  • Добавление пользователя в базу данных.

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

Реализация интерфейса ⚙️

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

💼 Реализация бизнес-логики

Создаю интерфейс с методом регистрации и входа в аккаунт.

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

Реализую бизнес-логику, реализовав созданных интерфейс. В конструкторе подключаю классы для работы с базой данных.

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

Метод регистрации

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

Метод входа в аккаунт

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

3. Контроллер 🌐

Создам новый класс в папке Controllers проекта Server , назову его AuthController . Добавлю в конструктор класса только что созданный сервис.

Добавлю два endpoint'а:

  • POST /register — для регистрации нового пользователя.

  • POST /login — для входа в аккаунт.

📌 Примечание: Swagger автоматически покажет доступные эндпоинты после запуска проекта.

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

4. Тестирование ✅

Запускаю проект. Открывается страница Swagger, где видны два созданных эндпоинта.

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

Регистрация 🆕

Открою POST /register и впишу в тело запроса:

{

"nickname": "vkatun",

"name": "vasya",

"email": "vasya@mail.ru",

"password": "password"

}

В итоге получу ответ с сообщением об успешной регистрации и статус-кодом 200!

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

🎉 Успех! Проверяю базу данных — в таблицах Users и Logs добавились соответствующие записи.

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

Таблица Users

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

Таблица Logs

Все работает!

Вход в аккаунт 🔑

Тестирую POST /login с правильными данными:

{

"emailOrNickname": "vkatun",

"password": "password"

}

В итоге получу ответ об успешной аутентификации и статус-кодом 200.

Создаю онлайн-сервис для чтения книг. День 4. Обработка первого запроса Программирование, Сервер, Длиннопост

Попробую ввести несуществующий логин и пароль:

{

"emailOrNickname": "vkatun123",

"password": "password"

}

и

{

"emailOrNickname": "vkatun",

"password": "password123"

}

Получу ответы:

{

"flag": false,

"message": "There is no account with this email or nickname."

}

и
{

"flag": false,

"message": "Invalid password"

}

соответственно

⚠️ Ошибка обработана корректно!

5. Заключение 🏁

Все работает корректно! Теперь можно приступить к реализации логики JWT, но это уже тема для другой статьи.

📚 Следите за обновлениями!

Показать полностью 17
3

Создаю онлайн-сервис для чтения книг. День 2-3. Подключение сервера к БД


👮 Ограничения платформы

Для реализации базовых функций используется .NET 7.0 со следующими компонентами:

  • Avalonia (для кроссплатформенного UI, если потребуется).

  • .NET Framework Core (базовые библиотеки и runtime).

  • .NET Framework Tools (инструменты разработки).

  • .NET Framework Design (шаблоны и архитектурные решения).

Создаю онлайн-сервис для чтения книг. День 2-3. Подключение сервера к БД Программирование, Программа, База данных, Длиннопост

🏗️ Проектирование структуры решения
Решение состоит из трёх проектов:

1. Server (Веб-API ASP.NET Core)

  • Роль: Точка входа приложения.

  • Содержит:

    • Эндпоинты API,

    • Middleware,

    • Конфигурацию сервера.

  • Зависимости:

    • ServerLibrary,

    • HelpLibrary,

    • Swashbuckle.AspNetCore.Filters.

2. HelpLibrary (Библиотека классов)

  • Роль: Хранение сущностей БД и DTO.

  • Пример сущности:

    public class User

    {

    public int Id { get; set; }

    public string Name { get; set; }

    }

3. ServerLibrary (Библиотека классов)

  • Роль: Бизнес-логика и работа с БД.

  • Функционал:

    • Аутентификация,

    • Валидация данных,

    • Взаимодействие с базой данных.

Создаю онлайн-сервис для чтения книг. День 2-3. Подключение сервера к БД Программирование, Программа, База данных, Длиннопост

Структура папок

📦 Установка пакетов Nuget

Для ServerLibrary:

  • Microsoft.AspNetCore.Identity

  • Microsoft.AspNetCore.Authentication.JwtBearer

  • Microsoft.EntityFrameworkCore

  • Microsoft.EntityFrameworkCore.SqlServer

  • Microsoft.EntityFrameworkCore.Tools

  • Microsoft.IdentityModel.Tokens

  • System.IdentityModel.Tokens.Jwt

Для Server:

  • Swashbuckle.AspNetCore.Filters (для документации API).


🔗 НАСТРОЙКА ССЫЛОК МЕЖДУ ПРОЕКТАМИ

  • Проект Server ссылается на:

    • ServerLibrary,

    • HelpLibrary.

Создаю онлайн-сервис для чтения книг. День 2-3. Подключение сервера к БД Программирование, Программа, База данных, Длиннопост

Пакеты и ссылки

🛠️ Генерация сущностей через scaffolding

Что это такое? - scaffolding

  1. Выполнение команды:

    Scaffold-DbContext "Server=.\SQLEXPRESS;Database=Readify;Trusted_Connection=True;encrypt=false;" Microsoft.EntityFrameworkCore.SqlServer

  2. Распределение кода:

    • DbContext → перемещён в ServerLibrary,

    • Сущности → остаются в HelpLibrary.

В конечном итоге сгенерировались сущности и контекст базы данных.

Создаю онлайн-сервис для чтения книг. День 2-3. Подключение сервера к БД Программирование, Программа, База данных, Длиннопост

Контекст базы данных

Создаю онлайн-сервис для чтения книг. День 2-3. Подключение сервера к БД Программирование, Программа, База данных, Длиннопост

Сущности

🗄️ Настройка подключения к БД

  1. Добавление строки подключения в appsettings.json:

    "ConnectionStrings":

    {

    "DefaultConnection": "Server=.\\SQLEXPRESS;Database=Readify;Trusted_Connection=True;Encrypt=false;"

    }

  2. Регистрация контекста БД в Program.cs:

    builder.Services.AddDbContext<ReadifyContext>(options =>

    {

    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection") ??

    throw new InvalidOperationException("Error to connection!"));

    });


✅ Итоги

  • Сгенерированы сущности БД через EF Core Scaffolding.

  • Настроено подключение к SQL Server.

  • Реализована трёхслойная архитектура:

    • Server (API),

    • HelpLibrary (DTO/Entities),

    • ServerLibrary (Бизнес-логика).

Проект готов к реализации бизнес-логики и разработке API!


Продолжение следует...

Показать полностью 4
4

Создаю онлайн-сервис для чтения книг. День 1. Проектирование БД


Всем привет, хочу вам показать свои шаги по созданию онлайн сервиса для чтения книг.

Создаю онлайн-сервис для чтения книг. День 1. Проектирование БД Программирование, База данных, SQL, Длиннопост

🤔 Идея проекта

Создание платформы для удобного чтения книг в формате PDF с синхронизацией прогресса на всех устройствах.
Ключевые фичи:

  • Интерактивные элементы для работы с текстом (закладки, заметки).

  • Интеграция с ИИ (например, перевод и анализ текста через DeepSeek).

  • Персонализированные рекомендации.

👀 Начало работы: проектирование БД

Спроектирована структура базы данных для поддержки функционала сервиса.
Представлю функционал в виде use-case диаграммы.

Создаю онлайн-сервис для чтения книг. День 1. Проектирование БД Программирование, База данных, SQL, Длиннопост

Базовый функционал

Как видно по фотографии, есть 2 роли — пользователь и администратор. При этом администратор может управлять всем содержимым сервиса, а пользователь только своим аккаунтом, и всем, что с ним связано.

Советуясь со своим внутренним голосом я составил структуру базы данных


🗃️ Структура базы данных

Users

  • id: INT, Primary Key, уникальный идентификатор пользователя (автоинкремент).

  • nickname: NVARCHAR(50), псевдоним пользователя.

  • description: NVARCHAR(150), описание профиля пользователя (опционально).

  • avatar_image_path: NVARCHAR(255), путь к изображению профиля пользователя (по умолчанию 'default-avatar.png').

  • name: NVARCHAR(100), имя пользователя.

  • email: NVARCHAR(150), уникальный адрес электронной почты пользователя.

  • password_hash: NVARCHAR(255), хэш пароля пользователя.

  • id_role: INT, идентификатор роли пользователя (по умолчанию 0). Связан с таблицей Roles.

  • is_banned: BIT, статус блокировки пользователя (по умолчанию FALSE).

  • created_at: DATETIME, дата и время создания записи.


Roles

  • id: INT, Primary Key, уникальный идентификатор роли (автоинкремент).

  • name: NVARCHAR(20), название роли (например, "admin" или "user").


BannedUsers

  • id: INT, Primary Key, уникальный идентификатор записи (автоинкремент).

  • id_user: INT, идентификатор заблокированного пользователя. Связан с таблицей Users.

  • ban_reason: NVARCHAR(200), причина блокировки (опционально).

  • banned_at: DATETIME, дата и время блокировки.


Books

  • id: INT, Primary Key, уникальный идентификатор книги (автоинкремент).

  • name: NVARCHAR(200), название книги.

  • description: NVARCHAR(250), краткое описание книги.

  • id_author: INT, идентификатор автора книги. Связан с таблицей Users.

  • cover_image_path: NVARCHAR(250), путь к обложке книги.

  • file_book_path: NVARCHAR(200), путь к файлу книги.

  • id_category: INT, идентификатор категории книги. Связан с таблицей Categories.

  • is_private: BIT, флаг приватности книги (0 — публичная, 1 — приватная).

  • created_at: DATETIME, дата и время создания записи (опционально).


Categories

  • id: INT, Primary Key, уникальный идентификатор категории (автоинкремент).

  • name: NVARCHAR(100), название категории.


Libraries

  • id: INT, Primary Key, уникальный идентификатор записи (автоинкремент).

  • id_author: INT, идентификатор пользователя, владеющего библиотекой. Связан с таблицей Users.

  • id_book: INT, идентификатор книги, добавленной в библиотеку. Связан с таблицей Books.

  • created_at: DATETIME, дата и время добавления книги в библиотеку.

  • progress_page: INT, номер текущей страницы, на которой находится пользователь (по умолчанию 0).


Bookmarks

  • id: INT, Primary Key, уникальный идентификатор записи (автоинкремент).

  • id_library: INT, идентификатор библиотеки, к которой относится закладка. Связан с таблицей Libraries.

  • page: INT, номер страницы, на которую сделана закладка.

  • comment: NVARCHAR(100), комментарий к закладке.

  • created_at: DATETIME, дата и время создания закладки.


BookReviews

  • id: INT, Primary Key, уникальный идентификатор отзыва (автоинкремент).

  • id_author: INT, идентификатор автора отзыва. Связан с таблицей Users.

  • id_book: INT, идентификатор книги, к которой относится отзыв. Связан с таблицей Books.

  • comment: NVARCHAR(500), текст отзыва.

  • rating: TINYINT, рейтинг книги (число от 0 до 5).

  • created_at: DATETIME, дата и время создания отзыва.


LikesReviews

  • id: INT, Primary Key, уникальный идентификатор записи (автоинкремент).

  • id_author: INT, идентификатор пользователя, который поставил реакцию. Связан с таблицей Users.

  • id_review: INT, идентификатор отзыва, к которому относится реакция. Связан с таблицей BookReviews.

  • reaction_type: TINYINT, тип реакции (например, лайк или дизлайк).

  • created_at: DATETIME, дата и время установки реакции.


Logs

  • id: INT, Primary Key, уникальный идентификатор записи (автоинкремент).

  • id_user: INT, идентификатор пользователя, совершившего действие. Связан с таблицей Users.

  • action: NVARCHAR(200), описание действия.

  • created_at: DATETIME, дата и время совершения действия.


UserSubscribers

  • id: INT, Primary Key, уникальный идентификатор записи (автоинкремент).

  • id_author: INT, идентификатор пользователя, на которого подписан другой пользователь. Связан с таблицей Users.

  • id_subscriber: INT, идентификатор пользователя, который подписан на другого пользователя. Связан с таблицей Users.

  • created_at: DATETIME, дата и время создания подписки.


UserSessions

  • id: INT, Primary Key, уникальный идентификатор записи (автоинкремент).

  • id_user: INT, идентификатор пользователя, которому принадлежит сессия. Связан с таблицей Users.

  • refresh: NVARCHAR(255), refresh токен.

  • expires_in: DATETIME, дата и время истечение refresh токена.

Создаю онлайн-сервис для чтения книг. День 1. Проектирование БД Программирование, База данных, SQL, Длиннопост

Таблица в Miro

С уверенностью 100% я могу сказать, что база данных будет меняться, но это будет на следующих этапах.

🔧 Следующие шаги

  1. Разработка сервера на .NET 7.0 для обработки HTTP-запросов.

  2. Реализация API для:

    • Авторизации/регистрации.

    • Управления книгами и библиотекой.

    • Синхронизации прогресса чтения.

  3. Интеграция с DeepSeek для AI-фич.


🚀 Продолжение следует...
Спасибо за поддержку! 👍

Показать полностью 2
4

Сессии, JWT, Access, Refresh

Статья представляет собой конспект из нескольких источников. Если у вас есть дополнения/поправки или замечания, пишите о них в комментариях.

Сессии, JWT, Access, Refresh Программирование, Длиннопост, Сервер, Access

Основные понятия

Регистрация

Клиент отправляет данные для входа на сервер. Сервер создает аккаунт и часто сразу проводит аутентификацию (в большинстве случаев).

Сессии, JWT, Access, Refresh Программирование, Длиннопост, Сервер, Access

Регистрация

Аутентификация

Процесс, в результате которого сервер узнает, кто вы такой. Клиент отправляет данные для входа, сервер проверяет их валидность. Если данные верны, сервер создает токен или идентификатор и отправляет его клиенту.

Сессии, JWT, Access, Refresh Программирование, Длиннопост, Сервер, Access

Аутентификация

Авторизация

Процесс, в результате которого сервер узнает, что вы можете делать, а что нет. Сервер выполняет авторизацию каждый раз, когда пользователь производит серверную операцию. Например, при отправке DELETE-запроса сервер проверяет токен и возвращает разрешение или отказ.

Сессии, JWT, Access, Refresh Программирование, Длиннопост, Сервер, Access

Авторизация

Логинизация

Логика на клиенте, которая отрабатывает в зависимости от успешности аутентификации. Например, флаг isAuthenticated меняется с false на true, и вместо кнопки "Войти" отображается иконка профиля.

Сессии, JWT, Access, Refresh Программирование, Длиннопост, Сервер, Access

Логинизация

Сессионная аутентификация (Session-based)

Как это работает:

  1. Аутентификация: Клиент отправляет данные для входа, сервер проверяет их и создает сессию. Сервер возвращает клиенту UUID сессии, который хранится в куках.

  2. Авторизация: Клиент отправляет куки на сервер, сервер проверяет валидность сессии и возвращает положительный ответ.

Плюсы:

  • Безопасность: сессии хранятся на сервере.

Минусы:

  • Bottleneck (подробнее): При большом количестве пользователей нагрузка на сервер увеличивается.

Сессии, JWT, Access, Refresh Программирование, Длиннопост, Сервер, Access

Аутентификация

Сессии, JWT, Access, Refresh Программирование, Длиннопост, Сервер, Access

Авторизация

Аутентификация на основе токенов (Token-based)

Как это работает:

  1. Аутентификация: Клиент отправляет данные для входа, сервер проверяет их и создает токен (например, JWT), который отправляется клиенту.

  2. Авторизация: При каждом запросе клиент отправляет токен в заголовке Bearer <token>. Сервер проверяет токен и возвращает положительный ответ.

Плюсы:

  • Нет необходимости хранить данные на сервере, что предотвращает bottleneck.

Минусы:

  • Менее безопасен, так как токен хранится на клиенте.

Перейдем на уровень ниже.

JWT токен

JWT (JSON Web Token) — это строка в формате base64, которая состоит из трех частей:

  1. Header (Заголовок)
    Содержит информацию о типе токена (JWT) и алгоритме шифрования.

  2. Payload (Полезная нагрузка)
    Содержит утверждения (claims) — данные о пользователе, сроке действия токена и т.д.

  3. Signature (Подпись)
    Хэш токена, созданный на основе алгоритма из заголовка и зашифрованный с помощью приватного ключа.

Сессии, JWT, Access, Refresh Программирование, Длиннопост, Сервер, Access

Пример токена

Важно: Не храните в токене пароли или другую важную информацию, так как токен можно раскодировать.

Access Token и Refresh Token

Access Token

Access Token — это токен, который клиент использует для доступа к защищённым ресурсам на сервере. Обычно он имеет короткий срок жизни.

Refresh Token

Refresh Token — это токен, который используется для получения нового Access Token, когда текущий Access Token истекает. Обычно он имеет длительный срок жизни.

Как работает:

  1. После успешной аутентификации сервер создает и отправляет клиенту Access Token и Refresh Token.

  2. Клиент сохраняет Refresh Token в безопасном месте (например, в HTTP-only куках).

  3. Когда Access Token истекает, клиент отправляет Refresh Token на сервер для получения нового Access Token.

  4. Сервер проверяет Refresh Token и, если он действителен, выдаёт новый Access Token.

Источники:
Аутентификация в ASP.NET Core — YouTube
Аутентификация. Сессии и JWT — YouTube
Что такое JWT, Access и Refresh токены — YouTube

Показать полностью 7
4

Создаю музыкальный сервис с ChatGPT: Миссия выполнима?

Вступление

Привет! Недавно я решил всерьез вкатываться в IT и вдохновился видео, где создают соцсеть с помощью ChatGPT. Решил провести похожий эксперимент и превратить свой курсовой проект в MVP музыкального сервиса.

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

То самое видео

Я не полный новичок в программировании, но и экспертом себя не назову. Моя оценка себя - даже не 3 из 10.

Получилось ли написать сервис с помощью ChatGPT? Спойлер: Нет. Но я сделал важные выводы и готов ими поделиться.

Шаг 1. Запрос в ChatGPT.

Первым делом я решил выбрать свой стек разработки. В голове у меня было, что я хочу использовать Java и React для проекта.

И в итоге мой запрос выглядел так:

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

Самый первый запрос

В ответ я получил инструкцию из нескольких пунктов, в котором ChatGPT по порядку рассказал что мне необходимо сделать.

Шаг 2. Прохожусь по пунктам.

Пункт 2. Исследование и планирование.

1.1 Функционал: Определи основные функции сервиса (например, стриминг музыки, создание плейлистов, рекомендации, социальные функции и т.д.).

Первым делом нужно было определиться с функционалом. Я хотел, чтобы мой сервис умел:

  • Регистрация/авторизация

  • Воспроизведение музыки

  • Добавление треков

  • Составление плейлистов

  • Поиск по сервису

  • Одинаковый уровень громкости

Дополнительные функции:

  • Визуальное сопровождение музыки

  • Показ текста песни

  • Социальные функции

  • Комментарии и оценки

  • Поддержка различных аудиоформатов

  • Настройка кастомной палитры сайта

  • Караоке

  • Рекомендации

Пункт 2. Исследование и планирование.

2.1 Техническое задание: Напиши подробное техническое задание, в котором опиши все функции и требования к проекту.

В этом пункте мне также помог ChatGPT, я подробно описал ему что я хочу получить на выходе.

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

Первая часть запроса

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

Вторая часть запроса

ChatGPT помог мне составить довольно неплохое ТЗ, которое я затем доработал и оформил.

2.2 Выбор технологий: Определи, какие технологии и библиотеки будешь использовать (например, Spring Boot для Java, Redux для управления состоянием в React и т.д.).

Я был вообще не знаком с технологиями и библиотеками, поэтому доверил выбор ChatGPT.

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

Запрос

Ответ:

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

Ответ ChatGPT

Я решил все это перенести в 1 место, создал проект в Miro и объединил все туда. Выглядело это так:

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

Доска в Miro на текущий момент

Пункт 3. Проектирование архитектуры.

3.1 Архитектура приложения: Определи архитектуру (например, микросервисная архитектура, монолит и т.д.).

3.2 База данных: Выбери подходящую СУБД (например, PostgreSQL, MongoDB) и спроектируй схему базы данных.

Я был знаком с монолитной архитектурой и работал с PostgreSQL, поэтому выбрал их.

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

Запрос

Если бы я не знал как работать с SQL, на этом этапе эксперимент мог закончиться.

Проектирование базы данных оказалось самым сложным этапом. ChatGPT путался в своих ответах, и мне пришлось долго править его сообщения. В конце концов, я утвердил финальную версию БД.

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

Схема БД в Miro

3.3 API: Спроектируй RESTful API или GraphQL для взаимодействия между фронтендом и бэкендом.

Для взаимодействия фронтенда и бэкенда я решил использовать RESTful API. И снова мне пришлось поправлять ChatGPT, чтобы получить корректные запросы.

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

Прошу конечную версию API-запросов

Все API-запросы я также задокументировал на доске в Miro.

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

Пункт 4. Разработка бэкенда.

4.1 Настройка окружения: Установи необходимые инструменты (JDK, Maven/Gradle, IDE).

Смешно, но на этом этапе возникли трудности с версией JDK, благо они решились 1 запросом.

4.2 Создание проекта: Создай новый проект на Java с использованием Spring Boot.

Я попросил описать структуру проекта, так как вообще не знал никаких паттернов.

Ответ ChatGPT:

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

Структура проекта

4.3 Реализация API: Реализуй основные эндпоинты для работы с пользователями, музыкой, плейлистами и т.д.

Я имел лишь базовые знания Java, поэтому просил ChatGPT написать код для каждой модели и эндпоинта. Постепенно я задавал вопросы о том, что происходит в коде, и понимал только часть.

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

Один из запросов

Таким способом я, используя ChatGPT написал всю логику эндпоинтов, без ошибок конечно не обошлось.

После того как я все написал, меня осенило, что нужно было все это тестировать :))

Решил запустить сервер. И, конечно же, не с первого раза все заработало. Ошибки, исправления, новые ошибки...

Как вдруг я увидел долгожданную надпись:

Создаю музыкальный сервис с ChatGPT: Миссия выполнима? Программирование, Длиннопост, ChatGPT

Ура, сервер запустился

Но... Даже если сервер запустился, это не значит что он не упадет спустя секунду xD. Ну конечно же он упал.

На этом этапе я решил завершить свой эксперимент, так как нашел ответ на свой вопрос.

Шаг 3. Какой же итог?

Может ли ChatGPT заменить программиста?

Мой эксперимент подтвердил: ChatGPT - не замена программисту, а мощный помощник. Он может сгенерировать код, предложить архитектуру и даже спроектировать базу данных. Но без понимания основ программирования и умения формулировать четкие запросы, добиться результата сложно.

Код проекта на GitHub: https://github.com/droptrigger/music-app

Мой Telegram-канал: t.me/CreateTrigger

Показать полностью 13
Отличная работа, все прочитано!