202 lines
7.4 KiB
Markdown
202 lines
7.4 KiB
Markdown
# Kimlik Doğrulama Sistemi
|
||
|
||
## Genel Bakış
|
||
|
||
Proje email + şifre tabanlı kimlik doğrulama kullanır. Başarılı girişte iki token döner:
|
||
|
||
| Token | Ömür | Kullanım |
|
||
|---|---|---|
|
||
| `access_token` | 15 dakika | Her korumalı isteğe `Authorization: Bearer` başlığı |
|
||
| `refresh_token` | 7 gün | Süresi dolan access token'ı yenilemek için |
|
||
|
||
Ek kural: Email doğrulaması tamamlanmadan login ve refresh işlemleri engellenir.
|
||
|
||
Algoritma: **HS256** (HMAC-SHA256)
|
||
|
||
---
|
||
|
||
## Akış Diyagramı
|
||
|
||
```
|
||
┌─────────┐ POST /api/v1/auth/register ┌─────────┐
|
||
│ Client │ ────────────────────────────────────► │ Server │
|
||
│ │ ◄──── 201 { user_id } + verify mail │ │
|
||
└─────────┘ └─────────┘
|
||
|
||
┌─────────┐ GET /api/v1/auth/verify-email ┌─────────┐
|
||
│ Client │ ── token linki ile ──────────────────► │ Server │
|
||
│ │ ◄──── 200 email verified ──────────── │ │
|
||
└─────────┘ └─────────┘
|
||
|
||
┌─────────┐ POST /api/v1/auth/login ┌─────────┐
|
||
│ Client │ ── { email, password } ──────────────► │ Server │
|
||
│ │ ◄── 200 { access_token, │ │
|
||
│ │ refresh_token } ───────────── └─────────┘
|
||
└─────────┘
|
||
|
||
┌─────────┐ GET /api/v1/me ┌─────────┐
|
||
│ Client │ ── Authorization: Bearer <access> ───► │ Server │
|
||
│ │ ◄── 200 { user_id, email, username } │ (auth │
|
||
└─────────┘ │ middleware)
|
||
└─────────┘
|
||
|
||
┌─────────┐ POST /api/v1/auth/refresh ┌─────────┐
|
||
│ Client │ ── { refresh_token } ────────────────► │ Server │
|
||
│ │ ◄── 200 { access_token } ───────────── └─────────┘
|
||
└─────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## Kayıt (`Register`)
|
||
|
||
**Dosya:** `app/accounts/controllers/user.go` → `Register()`
|
||
|
||
1. JSON body doğrulanır (`username` min 3, `email` geçerli format, `password` min 8 karakter, `confirm_password` min 8 karakter).
|
||
2. `password` ve `confirm_password` eşleşmesi kontrol edilir.
|
||
3. Şifre `bcrypt.DefaultCost` ile hash'lenir.
|
||
4. `User` kaydı veritabanına yazılır.
|
||
5. Rastgele bir email doğrulama token'ı üretilir ve kullanıcıya yazılır.
|
||
6. Kullanıcıya doğrulama maili gönderilir.
|
||
7. `email` alanı unique index'li; duplicate durumunda `409 Conflict` döner.
|
||
|
||
Not: Mail gönderimi başarısız olursa oluşturulan kullanıcı kaydı geri silinir.
|
||
|
||
```json
|
||
// İstek
|
||
{
|
||
"username": "ali",
|
||
"email": "ali@ornek.com",
|
||
"password": "gizli1234",
|
||
"confirm_password": "gizli1234"
|
||
}
|
||
|
||
// Başarılı yanıt 201
|
||
{ "message": "user created. please verify your email", "user_id": 1 }
|
||
```
|
||
|
||
## Email Doğrulama (`VerifyEmail`)
|
||
|
||
**Dosya:** `app/accounts/controllers/user.go` → `VerifyEmail()`
|
||
|
||
1. Query string içinden `token` alınır.
|
||
2. Token ile kullanıcı bulunur.
|
||
3. `email_verified=true`, `email_verified_at=now`, `email_verify_token=""` olarak güncellenir.
|
||
|
||
```json
|
||
// Başarılı yanıt 200
|
||
{ "message": "email verified successfully" }
|
||
```
|
||
|
||
---
|
||
|
||
## Giriş (`Login`)
|
||
|
||
**Dosya:** `app/accounts/controllers/user.go` → `Login()`
|
||
|
||
1. Email ile kullanıcı aranır.
|
||
2. `email_verified` kontrol edilir; doğrulanmamış hesaplara `403` dönülür.
|
||
3. `bcrypt.CompareHashAndPassword` ile şifre doğrulanır.
|
||
4. Her iki adımda da hata mesajı aynı tutulur — kullanıcı numaralandırma saldırısına karşı.
|
||
5. Başarıda access + refresh token döner.
|
||
|
||
```json
|
||
// İstek
|
||
{ "email": "ali@ornek.com", "password": "gizli1234" }
|
||
|
||
// Başarılı yanıt 200
|
||
{
|
||
"access_token": "eyJ...",
|
||
"refresh_token": "eyJ...",
|
||
"token_type": "Bearer"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Token Yenileme (`RefreshToken`)
|
||
|
||
**Dosya:** `app/accounts/controllers/user.go` → `RefreshToken()`
|
||
|
||
1. Body'den `refresh_token` alınır.
|
||
2. `JWT_REFRESH_SECRET` ile doğrulanır.
|
||
3. Kullanıcının `email_verified` durumu kontrol edilir; doğrulanmamışsa `403` döner.
|
||
4. Claims'ten `user_id`, `email`, `username` alanları kullanılarak yeni access token üretilir.
|
||
5. Refresh token yenilenmez (sliding window değil, sabit pencere).
|
||
|
||
```json
|
||
// İstek
|
||
{ "refresh_token": "eyJ..." }
|
||
|
||
// Başarılı yanıt 200
|
||
{ "access_token": "eyJ...", "token_type": "Bearer" }
|
||
```
|
||
|
||
---
|
||
|
||
## Google Login (OAuth 2.0)
|
||
|
||
**Dosya:** `app/accounts/controllers/user.go` → `GoogleLogin()` ve `GoogleCallback()`
|
||
|
||
Akış:
|
||
|
||
1. `GET /api/v1/auth/google/login`
|
||
2. Sunucu CSRF için `state` üretir, cookie'ye yazar ve `auth_url` döner.
|
||
3. Client kullanıcıyı `auth_url` adresine yönlendirir.
|
||
4. Google kullanıcıyı callback'e döndürür: `GET /api/v1/auth/google/callback?state=...&code=...`
|
||
5. Sunucu `state` doğrular, `code` ile Google'dan token alır.
|
||
6. Google `userinfo` verisi çekilir.
|
||
7. Kullanıcı email'e göre bulunur/oluşturulur, `SocialAccount(provider=google)` kaydı bağlanır.
|
||
8. Google ile gelen kullanıcı email'i doğrulanmış kabul edilir (`email_verified=true`).
|
||
9. Yerel `access_token` + `refresh_token` üretilip döndürülür.
|
||
|
||
Yeni endpointler:
|
||
|
||
- `GET /api/v1/auth/google/login`
|
||
- `GET /api/v1/auth/google/callback`
|
||
|
||
---
|
||
|
||
## GitHub Login (OAuth 2.0)
|
||
|
||
**Dosya:** `app/accounts/controllers/user.go` → `GitHubLogin()` ve `GitHubCallback()`
|
||
|
||
Akış:
|
||
|
||
1. `GET /api/v1/auth/github/login`
|
||
2. Sunucu CSRF için `state` üretir, cookie'ye yazar ve `auth_url` döner.
|
||
3. Client kullanıcıyı `auth_url` adresine yönlendirir.
|
||
4. GitHub callback'e döndürür: `GET /api/v1/auth/github/callback?state=...&code=...`
|
||
5. Sunucu `state` doğrular, `code` ile GitHub'dan token alır.
|
||
6. GitHub profil/email bilgisi çekilir.
|
||
7. Kullanıcı email'e göre bulunur/oluşturulur, `SocialAccount(provider=github)` kaydı bağlanır.
|
||
8. GitHub ile gelen kullanıcı email'i doğrulanmış kabul edilir (`email_verified=true`).
|
||
9. Yerel `access_token` + `refresh_token` üretilip döndürülür.
|
||
|
||
Yeni endpointler:
|
||
|
||
- `GET /api/v1/auth/github/login`
|
||
- `GET /api/v1/auth/github/callback`
|
||
|
||
---
|
||
|
||
## Güvenlik Notları
|
||
|
||
- Şifreler veritabanında **asla düz metin** tutulmaz; bcrypt hash'i saklanır.
|
||
- `Password` alanı modelde `json:"-"` ile işaretlidir — API yanıtlarında görünmez.
|
||
- Access ve refresh token farklı secret'larla imzalanır (`JWT_SECRET` / `JWT_REFRESH_SECRET`).
|
||
- Production'da her iki secret'ın en az 32 karakter uzunluğunda, rastgele olması gerekir.
|
||
- HTTPS zorunludur; token'lar aktarım sırasında şifrelenmez.
|
||
- Register adımında şifre uyumsuzluğu için `400 Bad Request` dönülür: `password and confirm_password do not match`.
|
||
|
||
---
|
||
|
||
## Swagger
|
||
|
||
- Swagger UI: `/swagger/index.html`
|
||
- Doküman üretme komutu:
|
||
|
||
```bash
|
||
$(go env GOPATH)/bin/swag init -g main.go
|
||
```
|