Разработать безопасный REST API сервис с функциями регистрации и аутентификации пользователей на Go.
- ✅ Регистрация пользователя с хешированием пароля (bcrypt)
- ✅ Вход в систему с выдачей JWT токена
- ✅ Защищенный эндпоинт для получения профиля (требует JWT)
- ✅ Защита от SQL-инъекций (параметризованные запросы)
Метод | Путь | Описание | Требует токен |
---|---|---|---|
POST | /register |
Регистрация пользователя | Нет |
POST | /login |
Вход в систему | Нет |
GET | /profile |
Получить профиль | Да |
GET | /health |
Проверка состояния | Нет |
secure-service/
├── main.go # Главный файл с запуском сервера
├── handlers.go # HTTP обработчики
├── models.go # Структуры данных
├── database.go # Работа с БД
├── auth.go # JWT и bcrypt
├── middleware.go # Проверка токена
├── docker-compose.yml # PostgreSQL в Docker
├── init.sql # Схема БД
├── .env # Конфигурация (создать из .env.example)
├── go.mod # Зависимости
└── README.md # Этот файл
# Создайте .env файл из примера
cp .env.example .env
# ВАЖНО: Измените JWT_SECRET в .env на свой ключ (минимум 32 символа)
nano .env
# Запустите PostgreSQL в Docker
docker-compose up -d
# Проверьте, что БД запустилась
docker-compose ps
# Скачайте Go модули
go mod download
Все файлы с пометкой TODO содержат заготовки функций, которые нужно завершить:
-
CreateUser()
- создание пользователя -
GetUserByEmail()
- поиск по email -
GetUserByID()
- поиск по ID -
UserExistsByEmail()
- проверка существования
-
HashPassword()
- хеширование паролей bcrypt -
CheckPassword()
- проверка паролей -
GenerateToken()
- создание JWT токенов -
ValidateToken()
- проверка JWT токенов
-
AuthMiddleware()
- проверка токенов
-
RegisterHandler()
- регистрация -
LoginHandler()
- авторизация -
ProfileHandler()
- профиль пользователя
// Импортируйте необходимые пакеты
import (
"golang.org/x/crypto/bcrypt"
"github.com/golang-jwt/jwt/v5"
)
// Реализуйте HashPassword
func HashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
return string(bytes), err
}
// ВАЖНО: Используйте параметризованные запросы!
func CreateUser(email, username, passwordHash string) (*User, error) {
query := `INSERT INTO users (email, username, password_hash) VALUES ($1, $2, $3) RETURNING id, created_at`
// Реализуйте...
}
func AuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 1. Получите токен из заголовка Authorization
// 2. Проверьте формат "Bearer <token>"
// 3. Валидируйте токен
// 4. Добавьте данные в контекст
// 5. Передайте управление дальше
}
}
Каждый обработчик содержит детальные комментарии с пошаговыми инструкциями.
# Запустите сервер
go run *.go
# В другом терминале тестируйте API
curl -X POST http://localhost:8080/register \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","username":"testuser","password":"SecurePass123"}'
curl http://localhost:8080/health
curl -X POST http://localhost:8080/register \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"username": "testuser",
"password": "SecurePass123"
}'
curl -X POST http://localhost:8080/login \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "SecurePass123"
}'
# Замените YOUR_JWT_TOKEN на токен из ответа /login
curl http://localhost:8080/profile \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
-
Пароли хешируются bcrypt
// ❌ НЕПРАВИЛЬНО user.Password = password // ✅ ПРАВИЛЬНО hash, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
-
SQL запросы параметризованы
// ❌ ОПАСНО - SQL инъекции! query := fmt.Sprintf("SELECT * FROM users WHERE email = '%s'", email) // ✅ БЕЗОПАСНО query := "SELECT * FROM users WHERE email = $1" db.QueryRow(query, email)
-
JWT токены проверяются
// ❌ БЕЗ ПРОВЕРКИ func ProfileHandler(w http.ResponseWriter, r *http.Request) { // Сразу возвращаем данные } // ✅ С ПРОВЕРКОЙ http.HandleFunc("/profile", AuthMiddleware(ProfileHandler))
-- ❌ ПЛОХО: пароль не захеширован
SELECT password_hash FROM users; -- "123456"
-- ✅ ХОРОШО: bcrypt хеш
-- "$2a$10$N9qo8uLOickgx2ZMRZoMye..."
// ❌ УЯЗВИМО
query := "SELECT * FROM users WHERE email = '" + email + "'"
// ✅ ЗАЩИЩЕНО
query := "SELECT * FROM users WHERE email = $1"
db.QueryRow(query, email)
// ❌ ОПАСНО
func ProfileHandler(w http.ResponseWriter, r *http.Request) {
// Нет проверки токена!
}
// ✅ БЕЗОПАСНО
http.HandleFunc("/profile", AuthMiddleware(ProfileHandler))
- PostgreSQL запускается через
docker-compose up
- Приложение подключается к БД и не падает
- Регистрация создает пользователя в БД
- Пароли хранятся как bcrypt хеш, НЕ в открытом виде
- Вход возвращает валидный JWT токен
- Токен можно декодировать на https://jwt.io
- Эндпоинт
/profile
требует токен (без токена → 401) - Эндпоинт
/profile
работает с правильным токеном - ВСЕ SQL запросы используют параметры
$1, $2...
- В коде НЕТ
fmt.Sprintf
для построения SQL
# Подключитесь к БД
docker exec -it secure_service_db psql -U postgres -d secure_service
# Проверьте хеши паролей
SELECT email, password_hash FROM users;
# Хеш должен начинаться с $2a$ или $2b$
\q
- Скопируйте токен из ответа
/login
- Вставьте на https://jwt.io
- Убедитесь, что содержит
user_id
,email
,username
-
БД не запускается
docker-compose down docker-compose up -d docker-compose logs postgres
-
Ошибки компиляции
go mod tidy go mod download
-
Сервер не запускается
- Проверьте .env файл
- Убедитесь, что JWT_SECRET длиннее 32 символов
- Проверьте, что PostgreSQL запущен
-
Тесты API не проходят
- Проверьте логи сервера
- Убедитесь, что все TODO функции реализованы
- Проверьте правильность JSON в curl запросах
- ✅ Регистрация и авторизация работают
- ✅ Пароли хешируются bcrypt
- ✅ JWT токены используются правильно
- ✅ SQL запросы параметризованы
- ✅ Защищенные эндпоинты требуют токен
- ✅ Код компилируется и запускается
- ❌ Пароли в открытом виде
- ❌ SQL инъекции возможны
- ❌ JWT не проверяются
- ❌ Код не компилируется