You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Следующим этапом будет реализация слоя приложения. Мы разместим там остальную часть бизнес-логики.
Немного теории
Слой приложения
Слой приложения - это сервисы.
В отличие от доменного слоя, слой приложения (application) уже знает о инфраструктурном слое (БД, удаленные сервисы...), но не знает о конкретной реализации - то есть использует через интерфейс. Этот факт нам пригодится позже.
Ещё один немаловажный факт - "входы-выходы" в слой приложения не являются доменными сущностями. То есть когда мы используем слой приложения извне, мы не используем сущности - только примитивы; и, если нужна структура, так называемые DTO - Data Transfer Object, который представляет из себя структуру без методов и, обычно, без конструктора, поля которого являются примитивами или другими DTO.
Также, на основе предыдущего PR. Здесь обязательно нужно сделать так, что те ошибки, которые случились по вине вызывающей стороны (например, невалидная почта или ненайденный пользователь) возвращать как Err<что-то там>, а не fmt.Errorf. А те ошибки, которые "незапланированные" - например, ошибка в БД - уже возвращать как
Мы будем использовать JWT аутентификацию. JWT токен - это строка, которая умеет:
нести в себе метаинформацию в заголовке (что строка является JWT токеном);
нести в себе полезную нагрузку (payload); в нашем случае payload-ом будет только userId;
шифроваться, чтобы токен нельзя было подделать.
Шифрование JWT может быть:
Симметричным, например, алгоритм HBAC (если я не ошибаюсь). Тогда, чтобы "сделать" ключ (подписать) и проверить, что он настоящий, используется один и тот же ключ. Ключ, считай, что просто строка) Он же иногда называется secret. Важно его никому не показывать!
Асимметричным, например, алгоритм RSA (да-да, который используется, например, для SSH). Тогда, чтобы подписать ключ используется приватный ключ, а для проверки подлинности - публичный.
В целом, больше теории можно почитать в гугле, а то я могу где-то ошибаться. Например, тут.
В тестах нужно будет расшифровывать JWT токен и проверять его payload.
Что нужно сделать?
Разработать AuthService. Можно расположить его в application/auth/auth.go.
Какие функции выполняет сервис аутентификации?
Регистрация, он же Register или Signup
Аутентификация, он же Login или Signin
Регистрация
О пользователе на момент регистрации известно:
email
password
В процессе регистрации:
проверяется валидность данных (в домене);
сохраняется в БД;
возвращается идентификатор пользователя.
Возможные ошибки:
пользователь с такой почтой уже есть;
невалидная почта;
слабый пароль.
Аутентификация
На вход:
email
password
В процессе аутентификации:
достается из БД запись о пользователе, если есть;
проверяется совпадение пароля и хэша;
возвращается JWT токен как строка, если успешно.
В JWT токене в качестве payload-а должен быть только userId.
Дополнительно: к вопросу о хранении интерфейсов
В Go принято хранить интерфейс в месте использования. Но мы немного отойдем от этой практики, и я аргументирую почему.
Что есть интерфейс? Условно, набор правил взаимодействия. Это в первую очередь методы. И, если бы у нас были только методы... то можно было бы спокойно класть интерфейс в слой приложения и не париться. Но в правила взаимодействия также включены и ошибки. Ошибки, которые возвращает инфраструктурный слой, например, о том, что пользователь не найден. Если ошибки инфраструктурного слоя будут лежать в слое приложения, инфраструктурный слой будет знать о слое приложения... ужс. Либо делить - интерфейсы в слое приложения, а ошибки... где-то отдельно. Короче говоря есть красивое решение.
Между инфраструктурным слоем и слоем приложения мы разместим пакет интерфейсов. Там будет сам интерфейс и набор ошибок, которые эти методы возвращают. Этот пакет можно разместить в infrastructure/interfaces/repository.go (потом будет понятно, почему).
(да, слой приложения возвращает свои ошибки, а не ошибки инфраструктуры).
Ещё важный момент -- инфраструктура работает с доменными сущностями. То есть условный UserRepository принимает UserId и возвращает User. Хотя иногда встречаю решения, где это сделано как в слое приложения - DTO и примитивы. Но нам дополнительные мапперы не нужны)
The text was updated successfully, but these errors were encountered:
Следующим этапом будет реализация слоя приложения. Мы разместим там остальную часть бизнес-логики.
Немного теории
Слой приложения
В отличие от доменного слоя, слой приложения (application) уже знает о инфраструктурном слое (БД, удаленные сервисы...), но не знает о конкретной реализации - то есть использует через интерфейс. Этот факт нам пригодится позже.
Ещё один немаловажный факт - "входы-выходы" в слой приложения не являются доменными сущностями. То есть когда мы используем слой приложения извне, мы не используем сущности - только примитивы; и, если нужна структура, так называемые DTO - Data Transfer Object, который представляет из себя структуру без методов и, обычно, без конструктора, поля которого являются примитивами или другими DTO.
Также, на основе предыдущего PR. Здесь обязательно нужно сделать так, что те ошибки, которые случились по вине вызывающей стороны (например, невалидная почта или ненайденный пользователь) возвращать как Err<что-то там>, а не
fmt.Errorf
. А те ошибки, которые "незапланированные" - например, ошибка в БД - уже возвращать какгде
op
- название пакета и метода, например:JWT
Мы будем использовать JWT аутентификацию. JWT токен - это строка, которая умеет:
Шифрование JWT может быть:
secret
. Важно его никому не показывать!В целом, больше теории можно почитать в гугле, а то я могу где-то ошибаться. Например, тут.
Для создания JWT токенов можно использовать библиотеку github.com/golang-jwt/jwt/v5.
В тестах нужно будет расшифровывать JWT токен и проверять его payload.
Что нужно сделать?
Разработать AuthService. Можно расположить его в
application/auth/auth.go
.Какие функции выполняет сервис аутентификации?
Регистрация
О пользователе на момент регистрации известно:
email
password
В процессе регистрации:
Возможные ошибки:
Аутентификация
На вход:
email
password
В процессе аутентификации:
В JWT токене в качестве payload-а должен быть только userId.
Дополнительно: к вопросу о хранении интерфейсов
В Go принято хранить интерфейс в месте использования. Но мы немного отойдем от этой практики, и я аргументирую почему.
Что есть интерфейс? Условно, набор правил взаимодействия. Это в первую очередь методы. И, если бы у нас были только методы... то можно было бы спокойно класть интерфейс в слой приложения и не париться. Но в правила взаимодействия также включены и ошибки. Ошибки, которые возвращает инфраструктурный слой, например, о том, что пользователь не найден. Если ошибки инфраструктурного слоя будут лежать в слое приложения, инфраструктурный слой будет знать о слое приложения... ужс. Либо делить - интерфейсы в слое приложения, а ошибки... где-то отдельно. Короче говоря есть красивое решение.
Между инфраструктурным слоем и слоем приложения мы разместим пакет интерфейсов. Там будет сам интерфейс и набор ошибок, которые эти методы возвращают. Этот пакет можно разместить в
infrastructure/interfaces/repository.go
(потом будет понятно, почему).Наполнение будет такого рода:
И использование:
(да, слой приложения возвращает свои ошибки, а не ошибки инфраструктуры).
Ещё важный момент -- инфраструктура работает с доменными сущностями. То есть условный UserRepository принимает UserId и возвращает User. Хотя иногда встречаю решения, где это сделано как в слое приложения - DTO и примитивы. Но нам дополнительные мапперы не нужны)
The text was updated successfully, but these errors were encountered: