Пишем gRPC сервис на Go - Сервис авторизации / УЛЬТИМАТИВНЫЙ гайд
HTML-код
- Опубликовано: 19 июн 2024
- Пишем полноценный gRPC сервис с современной архитектурой. Также:
- Напишем контракт protobuf, разберемся с кодогенерацией
- Научимся работать с ошибками и логами
- Настроим миграции для БД
- Настроим автоматический деплой через GitHub Actions, напишем для этого workflow
- и др.
Исходный код проекта (версия кода с зафиксированной версией на момент выхода гайда): github.com/GolangLessons/sso/...
Текстовая версия в виде инструкции: slc.tl/ygj4t
Полная текстовая версия гайда: habr.com/ru/articles/774796/
Облачный сервер для для gRPC-сервиса: slc.tl/s0kla
--------
Другие мои ролики, дополняющие текущий:
REST API - URL Shortener: • Пишем REST API сервис ...
Интерфейсы по месту использования: • Почему интерфейсы лучш...
Моки и их генерация: • Генерация и использова...
Использование SQLite в Go: • SQLite в Golang - как ...
----
👾 t.me/ntuzov - мой канал в Telegram.
Пишу в нём много интересного: гайды, которых нет на RUclips, интересные мысли про разработку, новости и анонсы всех моих активностей и др.
👀 GoLang Digest: t.me/golang_digest - мои регулярные подборки интересных материалов по Go.
🗣️ Наше сообщество GopherClub: t.me/+zsSZ63wEJDs3NGVi
Лучшее русскоязычное Go-сообщество с очень приятной атмосферой, без токсиков. Вежливо и терпеливо помогаем новичкам, конструктивно дискутируем с профессионалами и т.п.
Здесь также присутствуют все звезды Go-сообщества и представители интересных компаний 😄
❤️ Если у вас есть желание поддержать развитие канала:
Секретный телеграм-канал:
- В рублях: t.me/+1UPXV_DGnG1mODJi
- В евро: t.me/+hedI8LevYTc5MDM6
Boosty: boosty.to/nikolay.tuzov
Patreon: / tuzov
----
Тайм-коды:
00:00 Вступление
01:00 Мой Телеграм-канал, зачем на него подписываться
02:04 Теоретический ликбез
06:49 SSO или Auth?
07:58 Авторизация и аутентификация - в чем разница?
08:31 Архитектура авторизации в нашем сервисе
09:51 Что такое JWT и зачем он нужен?
14:01 Архитектура приложения
16:33 Protobuf контракт
31:24 Пишем SSO: каркас и структура проекта
38:03 Конфигурация приложения
52:32 Настраиваем логгер - log.slog
01:03:56 gRPC-сервер и хэндлеры
01:18:48 Запуск и проверка приложения
01:22:04 Graceful shutdown
01:27:08 Хэндлер Login()
01:34:28 Хэндлер Register()
01:36:01 Хэндлер IsAdmin()
01:36:53 Сервисный слой
01:46:27 Метод RegisterNewUser() и хэширование паролей
01:52:05 Метод Login() и сравнение хэшей паролей
01:58:00 Создание JWT-токена
02:04:45 Миграции базы данных
02:23:05 Слой работы с данными: реализация Storage
02:32:09 Собираем все компоненты воедино
02:37:11 Пишем функциональные тесты
03:05:22 Интеграция с другим сервисом: URL Shortener
03:15:05 Покупка облачного сервера для деплоя
03:19:16 GitHub Actions: настраиваем автоматический деплой
03:36:53 Тестируем задеплоенный сервис
03:41:23 Заключение
03:41:35 Наше сообщество - Gopher Club
03:43:16 Как поддержать развитие канала
#golang #ntuzov
Текстовая версия в виде инструкции: slc.tl/ygj4t
Полная текстовая версия гайда: habr.com/ru/articles/774796/
Облачный сервер для для gRPC-сервиса: slc.tl/s0kla
👾Мой канал в Telegram: t.me/ntuzov
Пишу там новости, анонсы своих активностей и просто интересные мысли
Также с его помощью я получаю от вас оперативный фидбэк по роликам - что нравится, что не нравится, какой ролик делать следующим и т.п.
Понимание того кто находится перед нами - это идентификация, а аутентификация это уже проверка того что пользователь идентифицирован верно, грубо говоря что Вася это действительно Вася а не Петя которые пытается зайти под пользователем Васей. Так же как в ООП здесь тоже есть свои 3 кита безопасновти - Идентификация, аутентификация и авторизация.
Здравствуйте Николай! В текстовой версии вот тут Команда для генерации будет следующей: неполная команда при копировании!
4:08 Зачем самому изобретать велосипед, когда есть GZip сжатие на лету? Для json у меня соотношение достигало 10:1.
Вот убирать _ненужные в данный момент_ данные, либо какие-либо _промежуточные_ данные, _необязательные вообще для пользователя_ стоит.
Большой длинный многословный комментарий бесконечный благодарности чтобы алгоритмы ютуба вывели ролик в топ
Потрясающая подача материала. Спасибо Вам огромное.
Спасибо за такой, не побоюсь сказать, титанический труд. Очень мало подобных видео 👍
Это мне на несколько дней плотных занятий.
Господи, Николай, это невероятная работа - спасибо вам огромное за полный обзор ВСЕГО. Я из этого видео очень многому научился и узнал разные практики, например с логгированием, архитектурой проекта, и всякие штуки по типу MustRun. Думаю такие мелочи помогли мне пройти тестовое задание! Очень приятно смотреть такое. Не останавливайтесь!
Спасибо за видео, ждал его как второе пришествие ♥
Лайк не глядя)) Что короткие, что длинные ролики - топовые у тебя.
Весь месяц ждал только это видео❤
Огромное СПАСИБО за такие гайды по гошке!
Очень круто раскрываешь тематику.
Удивительно ясные и логичные объяснения действий и своего выбора. Смотрел и наслаждался!
Как раз недавно начинал делать свои поделки и осваивать gRPC, спасибо за еще один хороший материал по этой теме
Автор плиз делай больше таких уроков полезных, чтоб мы простые работяги могли твои уроки брать и учиться собирать сайта с нуля. плиз. Я думаю много ребят поддержат. Мир вашему дому
11:50 Харасмент через жвт токены, кибербулинг выходит на новый уровень
Ролик и автора в ТОП! Огромная благодарность ❤
Неужели ролики такого крутого уровня можно найти на Ютубе.
Спасибо, приятно посмотреть!
спасибо за труд, очень полезная информация ❤
Братец, это просто огромная работа, большое тебе спасибо за бесплатный контент такого уровня, было очень интересно. Лайк, подписка.
Спасибо огромное, только погружаюсь в Go и выпало ваше видео, с удовольствием посмотрел, действительно огромная польза для комьюнити)
Благодарен за видео. Очень помогает развиваться.
Спасибо за твой труд, очень полезно!
Отличный ролик, интересная альтернатива CRUDа с подробными пояснениями.) Спасибо! Всех Благ!
На роликах данного канала я обычно использую лайки вместо "посмотреть позже". Автор как всегда выдал лютешую базу. Ждём продолжения
Давно ждал. Спасибо большое!
Спасибо огромное за такой прекрасный гайд! Если будет возможность в отдельном ролике настроить пайплайн, будет вообще обалденно :)
Спасибо! Огромная польза для меня, я сейчас перехожу с ноды на гошку
Продолжай в том же духе! Один из лучших каналов на ютубе про гошечку
Вот это трудовая мощь, спасибо!
Благодарю за такой труд 🙏🏻🌹🌹🌹 Процветания каналу и всем здоровья 🙏🏻🌹🌹🌹особенно Николаю за такой труд
Мы ждали и наконец-то дождались
Очень крутой ролик, спасибо большое за знания. Интересно было бы увидеть использование docker в вашем исполнении, так как вы довольно исчерпывающе рассказываете и показываете всякие нюансы.
Темы для новых роликов теперь можно предлагать здесь: ntuzov.canny.io/golang-lessons/p/scheduler
Тогда точно не потеряется, не забудется, и сможем оценить востребованность темы.
А чтобы точно сдлеать это правильно, советую сначала прочитать этот пост: t.me/ntuzov/355
Спасибо за твои труды!!!
Спасибо спс, только искал видео по gRPC, толкового ничего не нашел, а на собесах спрашивают😊
Спасибо! Наверняка есть какие-то неточности, но в целом редкое на Ютубе видео, где разобрана не отдельная деталь, а вся конструкция в целом
спасибо за проделанную работу!
Спасибо! Очень познавательный видос.
Это было прекрасно, спасибо! )
Подобных по содержанию и насыщенности роликов, если и делают в рускоговорящем сегменте, то единицы, однозначно лайк и уважение
Тут про gRpc только несколько хендлерочков, очень жду если расскажешь и покажешь(очень ждал), примеры как использовать разные варинаты gRpc на практике. То есть server Stream, client Stream и комбинацию этих подходов. В любом случае, сделал невероятный труд. Красава
Коммент в поддержу твоего канала. Спасибо!
Титанический труд, спасибо!
Спасибо - хотим еще таких видео!)
Спасибо🙏💕 большое дай Бог вам здоровья
Сам PHP разраб. Решил посмотреть под работу видос и не смог работать, потому что смотрел видос)
Очень все доходчиво обясняет автор. Спасибо. Посмотрю после работи)
Ого, очень приятно видеть, что мой ролик настолько затягивает ❤️
Спасибо за ролик
Круто! Да это ж круто!
мне больше нравится для кода в /internal логировать ошибку сразу после получения и передавать оригинал вызывающему коду, а вот для кода в /pkg уже можно и обернуть...
Кстати, в показанном подходе определения интерфейса более серьёзный недостаток, это если в сигнатуре метода появляется пользовательский тип - тогда абстракция протекает из-за связи или приходится писать нецензурный кастинг.
Топ контент! Лайк и комментарий в поддержку и для продвижения канала!
Легендарный автор! Я по его роликам учился) лайк не глядя
Мощно, крутяк :)
Хотелось бы в ролике увидеть про использование связки gRPC и Kafka
Автолайк Коляну, топовый контент, красава!
Жду такой же видос, только по брокерам
Лучший!!
ГИГАНТСКОЕ СПАСИБО НИКОЛАЙ!За флаг РК как обычно уважение🇰🇿🦅🔥
Николай Топовый профессионал!
Спасибо)
Круто
Спасибо за видео, крутой материал. Есть вопрос. А в каком месте реализуется регистрация и логин в реальных условиях. Например если это фронт, то чтобы получить токен, можно реализовать запрос через js, или есть более лучшие подходы?
Николай, подскажите - в следующем видео про permissions какой паттерн планируете использовать? ABAC или RBAC? Очень надеюсь и хотелось бы увидеть реализацию именно ABAC, в силу наибольшей гибкости. К слову приходилось реализовывать ABAC на nodejs, но очень интересно посмотреть на все это дело на go.
Привет. Супер обучалки. Подписался. У тебя есть контент где ты учишь делать микросервисы? Желательно с тестированием и логгированием😊
ой, за взрослое всегда лайк
Thanks
Благодарю автора за годный материал - это во первых.
А во-вторых хотел спросить/предложить:
Нормально ли, чтобы не передавать три раза storage в функцию, объявить интерфейс Service и встроить в него все те три интерфейса, образец:
type Service interface {
package.UrlSaver
package.AppProvider
package.UserProvider
}
И потом передавать его одного в функцию-конструктор New(log *slog.Logger, port int, tokenTtl time.Duration, service package.Service)
?
Несколько вопросов
Если запускать миграции в самом приложении после инициализации базы? без отдельного мигратора. это ок? например пакетом goose?
Нужен ли такой сложный github actions конфиг связанный с systemd, не проще ли создать пакет и с помощью docker Watchtower ждать изменений в образе что хранится в пакетах на гитхаб?
тупа царь
Спасибо за труд, в IDE jetbrain нужно задавать env не используя скобок “ ” - CONFIG_PATH=config/local.yaml , нужно задавть в меню File -> Settigs ->GO-> Go modules CONFIG_PATH=config/local.yaml !!!!! Вопрос почему здесь панику используешь в конфиге, а в рест API фатал пишешь?
Доброго дня. Вцелом крутой ролик.
Но есть вещь, которая прям тригерит "Нельзя передавать роль is_admin в токене, если захотим лишить человека прав, а токен 1 час живёт, то не лишим".
Ну в рамках такого пет-проекта - может и да.
А Если у тебя KeyCloack + Kong ? И лишим и довольно быстро, и без проблем. Logout ему сделаем и всё.
Как например браузер будет определять is_admin? Кроме как по токену?
Делать ему целую ручку для этого - ну вот тебе и нагрузка на сервер.
Ну или если ролевая модель сложнее чем Админ, не Админ.
Вобщем стоило сказать что описанные проблемы они касаются только текущей реализации пета-демки.
Описанная проблема относится в целом к jwt. Мы также и не можем сразу разлогинить человека, максимум что можно сделать - это запретить обновлять токен, чтобы токен человека не смог обновиться, но опять таки у человека все еще будет доступ все время пока живет текущий токен.
Решение для этого простое - либо уменьшаем время жизни аксесс токена до маленьких значений(например 5 минут) либо старые добрые сессии)
Будет ли видео по прекрутке фронта к сервису авторизации?
Николай Тузов, спасибо вам за контент. Я сам самоучка , работаю как веб-разработчик начинал с курсов и фронта, сейчас посматриваю в сторону бэка, php честно не хочется углубляться хотя каждый день с ним сталкиваюсь. Николай Тузов хотел спросить на площадках много старых курсов по go, есть ли разница от версий с какой можно начать или как js просто обрастает новыми фичками ?
Большой разницы нет. Можно изучить курсы / книги по старым версиям, а потом ознакомиться с нововведениями. Но если есть возможность, лучше выбирать актуальный материал.
@@nikolay_tuzov спасибо за ответ, будем вливаться в Go
Может прикольней было бы не встраивать все интерфейсы Storage в сервис Auth по одному, а определить общий интерфейс, который бы объединял все мелкие интерфейсы. И в случае рефакторинга не составило бы труда отделить конкретный интерфейс, выпилив его из общего.
Столкнулся с такой проблемой: при написании TestLogin_FailCases, тест выдавал ошибку на строчке require.Contains(t, err.Error(), tt.expectedErr), смотрю в логах, а там проверяется наличие "invalid email or password" (1) в "invalid argument" (2). Проблему решил, заменив текст ошибки в grpc хендлере с (2) на (1). Вопрос, не стоит ли как - то стандартизировать внутри сервиса название подобных ошибок?
P.S. ролик очень крутой, автору большое спасибо за проделанную работу!
Подскажите, пожалуйста, верно ли, что protobuf преобразует ключи как запросов к сервису, так и ответов?
И клиент на своей стороне декодирует ответ от сервиса с помощью контракта
А почему все методы сервисного слоя принимают Context, но нет самой проверки на предмет отмены этого контекста? Какой в нем тогда смысл? Спасибо.
за флаг отдельный лайк ❤
А есть ли варианты для бесплатного деплоя, и какой лучше?
Здравствуйте, Николай, вы в ролике упомянули gtpr или как то так произнесли это сокращение, но в инете совсем нет ничего про это, можете написать , как по правильному
General Data Protection Regulation (EU GDPR) - регламент по защите данных в ЕС
Для чего мы используем Prepare в данном примере, можете объяснить?
Почему services знает о storage(импортируем ошибки из него)?
2:30:44 на 65 строке нет ли риска sql иньекции? Пришел с другого яп и там это через orm защищено от подобных моментов.
Нет, т.к. мы используем метод db.Prepare(). Значения будут экранированы.
не нашел коммента, а что за терминал используете?
За флаг Казахстана отдельное спасибо 🇰🇿😊
если вдруг, у Вас возник затык с установкой protoc, и вроде все рекомендации и документации прочтены, а команда protoc --version ругается - просто добавьте в переменную среды в Path путь к файлу protoc-25.1-win64\bin
посмотрел два раза, пока ничего не понятно, сейчас начну заново
Ты в закрытом канале смотрел? )
Ещё бы деплой на gitlab ci/cd был и была бы совсем абсолютная вкуснятина, но и так очень круто, благодарю!
А зачем gitlab, если есть github? Для пет-проектов идеально, а на работе этим девопсы занимаются обычно.
Николай, мне очень понравился ваш гайд и вдохновившись решил привнести свой вклад и облечгить людям установку grpc-go плагина и protoc. Я заметил что мой комментарий с ссылкой на репо был сразу удален :( Почему я не могу поделиться решением, которое в разы упращает процесс установки?
Я не удалял, возможно ютуб автоматом блокирует такое, но это странно. Попробуй ещё раз.
@@nikolay_tuzov в таком случае извините, не берите на свой счет :) Я погуглил и вы правы, youtube действительно автоматически удаляет комментарии с ссылками.
44:51 не избыточно называть структуру GRPCConfig, при условии что она находится в пакете config?
Возможно, да
А не подскажите, что за текстовый редактор используется на 33:00 ?
Это не редактор, это просто скриншот ) А изначально текст был написан в Obsidian
@@nikolay_tuzov понял. А что за просмотрщик картинок, в котором открыт скриншот?
@@buginsystem8925 это окошко самого же скриншотера - Shottr. Хорошая штука)
Логером удобно логировать имя файла и строку из которой собственно лог.
А если вы обновите код и строчки немного сдвинутся? И при этом вам потребуется посмотреть вчерашние логи, когда версия кода была другая? А если позавчерашние, когда версия кода была ещё более старая?
Можно, конечно, ещё и версию кода логировать, но это слишком уж запарно - разбираться к какой версии что относится, и что было в этой строчке в такой-то версии.
Файл и строка берется не в месте логирования. В Го можно получить стек вызовов через runtime / Caller, логгер это может сделать сам.
По поводу изменений версий: у нас с этим за много лет проблем не было )
Более того, если багрепортер указал в репорте версию и номер строки из лога не соответствует коду этой версии, то это сразу указывает, что багрепортер где-то ошибся )
@@Carimusa не очень понял, что значит "берется не в месте логирования", и как это связано с тем что я написал?
Использование runtime / Caller довольно затратная и не быстрая штука, не во всех случаях подойдет.
Багрепортер, это отдельная история вообще. Я больше про то, чтобы удобно было в логах разбираться, и чётко понимать, к какой функции относится та или иная запись.
@@nikolay_tuzov
Согласен, затратно и не быстро, но на практике, по умолчанию, на продакшене логируются ошибки и немного информационных сообщений. Если собирается дебаг логи, то затраты на io оказываются значительно больше, чем все остальное.
По поводу смещения номера строки, то это больше специфика нашего проекта.
У нас не бывает логов, без привязки к версии продукта.
Подскажите пожалуйста, как импортировать пакет log/slog
С версии 1.21 он включен в стандартную библиотеку, если его нет просто обнови go.
Несколько минут описываешь I из SOLID, не упоминая сам SOLID.
Можно же просто сказать «вот, есть такой принцип, используйте его».
Собственно, все эти паттерны и наборы принципов существуют для упрощения коммуникаций.
Аус!
Почему logger в internal а не pkg?
А зачем нужен бранч guide-version?
Я буду дорабатывать проект, и он будет отличаться от того, что покзан в ролике. В этой ветке версия будет зафиксирована.
Реально ли стать джуном на Golang без опыта или нужно начать с другого языка?
Я думаю, вполне реально. Но лучше не верить мне на слово, а проверять эту инфу более тщательно - изучить вакансии, поспрашивать в чатах.
Вообще, я знаю пару примеров ребят, которые начали именно с Го, и у которых всё получилось.
А где ошибка «Вы ввели пароль пользователя X, проверьте правильность введённого email»? :)
Эпизод: пишем функциональные тесты
Ручку на добавление аппки... А авторизовывать эту ручку кто будет? Этот же сервис? =)
Спасибо! Ну гайд скорее исчерпывающий, а не ультимативный. 🤔
Скажите, зачем везде контекст прокидывать?
а что за утилита для автогенерациии внутри приложения?
спасибо
GitHub Copilot, у меня про него есть отдельный ролик
@@nikolay_tuzov спасибо
Совет. Не ставьте утилиту proto через apt install - может установиться старая версия, и тогда будут проблемы. Ставьте через вариант Install pre-compiled binaries.