357 lines
8.4 KiB
Markdown
357 lines
8.4 KiB
Markdown
# CORS 403 Hatası Çözümü
|
||
|
||
## ❌ Problem
|
||
|
||
```
|
||
OPTIONS https://goauth.beyhano.net.tr/v1/auth/login
|
||
Status: 403 Forbidden
|
||
Origin: https://nextgo.beyhano.net.tr
|
||
```
|
||
|
||
### Hata Detayları:
|
||
- **Frontend Origin:** `https://nextgo.beyhano.net.tr`
|
||
- **Backend:** `https://goauth.beyhano.net.tr`
|
||
- **HTTP Method:** OPTIONS (preflight request)
|
||
- **Status:** 403 Forbidden
|
||
- **Sorun:** CORS middleware sadece `localhost:3000`'e izin veriyor
|
||
|
||
---
|
||
|
||
## ✅ Çözüm
|
||
|
||
### 1. Dynamic CORS Middleware Aktif Edildi
|
||
|
||
**Önce (main.go):**
|
||
```go
|
||
// Hardcoded CORS - sadece localhost
|
||
r.Use(cors.New(cors.Config{
|
||
AllowOrigins: []string{"http://localhost:3000"},
|
||
...
|
||
}))
|
||
```
|
||
|
||
**Sonra (main.go):**
|
||
```go
|
||
// Dynamic CORS - Database'den okuyor
|
||
settingsService := services.NewSettingsService()
|
||
r.Use(middlewares.DynamicCorsMiddleware(settingsService))
|
||
```
|
||
|
||
### 2. Whitelist'e Origin Ekleme
|
||
|
||
Production origin'ini whitelist'e ekleyin:
|
||
|
||
```bash
|
||
# Admin login
|
||
TOKEN=$(curl -s -X POST https://goauth.beyhano.net.tr/v1/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"email":"admin@gauth.local","password":"Admin@123"}' | jq -r '.access_token')
|
||
|
||
# Frontend origin'ini whitelist'e ekle
|
||
curl -X POST https://goauth.beyhano.net.tr/v1/settings/cors/whitelist \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"origin": "https://nextgo.beyhano.net.tr",
|
||
"description": "Production Next.js frontend"
|
||
}'
|
||
```
|
||
|
||
**Başarılı Yanıt:**
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"origin": "https://nextgo.beyhano.net.tr",
|
||
"description": "Production Next.js frontend",
|
||
"is_active": true,
|
||
"created_by": "admin@gauth.local",
|
||
"created_at": "2026-02-05T...",
|
||
"updated_at": "2026-02-05T..."
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 Dynamic CORS Middleware Nasıl Çalışır?
|
||
|
||
### Akış:
|
||
|
||
1. **Request gelir** → `Origin` header kontrol edilir
|
||
2. **Database kontrolü** → Whitelist/Blacklist'ten origin aranır
|
||
3. **Cache kontrolü** → Redis'te var mı? (1 saat TTL)
|
||
4. **Karar:**
|
||
- ✅ Whitelist'te var → İzin ver
|
||
- ❌ Blacklist'te var → Reddet (403)
|
||
- ❌ Hiçbirinde yok → Reddet (403)
|
||
|
||
### Code (`dynamic_cors_middleware.go`):
|
||
|
||
```go
|
||
func DynamicCorsMiddleware(settingsService *services.SettingsService) gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
origin := c.Request.Header.Get("Origin")
|
||
|
||
// Check if origin is allowed
|
||
allowed, err := settingsService.IsOriginAllowed(origin)
|
||
|
||
if !allowed {
|
||
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
|
||
"error": "Origin not allowed by CORS policy",
|
||
})
|
||
return
|
||
}
|
||
|
||
// Set CORS headers
|
||
c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
|
||
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization")
|
||
c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
|
||
c.Writer.Header().Set("Access-Control-Max-Age", "86400") // 24 hours
|
||
|
||
// Handle preflight requests
|
||
if c.Request.Method == "OPTIONS" {
|
||
c.AbortWithStatus(http.StatusNoContent)
|
||
return
|
||
}
|
||
|
||
c.Next()
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 Production Deploy Sonrası Yapılacaklar
|
||
|
||
### 1. Container'a Bağlan
|
||
|
||
Dokploy dashboard veya SSH ile:
|
||
```bash
|
||
docker exec -it app_auth_central sh
|
||
```
|
||
|
||
### 2. Admin Kullanıcı Oluştur
|
||
|
||
```bash
|
||
./main seed-admin
|
||
```
|
||
|
||
**Credentials:**
|
||
- Email: `admin@gauth.local`
|
||
- Password: `Admin@123`
|
||
|
||
### 3. Admin Login (Local veya cURL)
|
||
|
||
```bash
|
||
TOKEN=$(curl -s -X POST https://goauth.beyhano.net.tr/v1/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"email":"admin@gauth.local","password":"Admin@123"}' | jq -r '.access_token')
|
||
|
||
echo "Token: ${TOKEN:0:30}..."
|
||
```
|
||
|
||
### 4. Frontend Origin'lerini Ekle
|
||
|
||
#### Development:
|
||
```bash
|
||
curl -X POST https://goauth.beyhano.net.tr/v1/settings/cors/whitelist \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"origin": "http://localhost:3000",
|
||
"description": "Local development"
|
||
}'
|
||
```
|
||
|
||
#### Production (Next.js):
|
||
```bash
|
||
curl -X POST https://goauth.beyhano.net.tr/v1/settings/cors/whitelist \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"origin": "https://nextgo.beyhano.net.tr",
|
||
"description": "Production Next.js frontend"
|
||
}'
|
||
```
|
||
|
||
#### Staging (opsiyonel):
|
||
```bash
|
||
curl -X POST https://goauth.beyhano.net.tr/v1/settings/cors/whitelist \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"origin": "https://staging.beyhano.net.tr",
|
||
"description": "Staging environment"
|
||
}'
|
||
```
|
||
|
||
### 5. Doğrulama
|
||
|
||
```bash
|
||
# Whitelist'i kontrol et
|
||
curl -X GET https://goauth.beyhano.net.tr/v1/settings/cors/whitelist \
|
||
-H "Authorization: Bearer $TOKEN" | jq '.[] | {origin, is_active}'
|
||
```
|
||
|
||
**Beklenen Yanıt:**
|
||
```json
|
||
[
|
||
{
|
||
"origin": "https://nextgo.beyhano.net.tr",
|
||
"is_active": true
|
||
},
|
||
{
|
||
"origin": "http://localhost:3000",
|
||
"is_active": true
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
## 🧪 Test
|
||
|
||
### Frontend'den Test:
|
||
|
||
```javascript
|
||
// Next.js veya React'ten
|
||
fetch('https://goauth.beyhano.net.tr/v1/auth/login', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
email: 'test@example.com',
|
||
password: 'password123'
|
||
})
|
||
})
|
||
.then(res => res.json())
|
||
.then(data => console.log(data))
|
||
.catch(err => console.error(err));
|
||
```
|
||
|
||
### Browser Console'dan Test:
|
||
|
||
```javascript
|
||
// Preflight request'i test et
|
||
fetch('https://goauth.beyhano.net.tr/v1/auth/login', {
|
||
method: 'OPTIONS',
|
||
headers: {
|
||
'Access-Control-Request-Method': 'POST',
|
||
'Access-Control-Request-Headers': 'content-type'
|
||
}
|
||
})
|
||
.then(res => {
|
||
console.log('Preflight Status:', res.status); // 204 olmalı
|
||
console.log('CORS Headers:', res.headers);
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 CORS Headers Özeti
|
||
|
||
Request başarılı olduğunda aşağıdaki header'lar dönmeli:
|
||
|
||
```http
|
||
Access-Control-Allow-Origin: https://nextgo.beyhano.net.tr
|
||
Access-Control-Allow-Credentials: true
|
||
Access-Control-Allow-Headers: Origin, Content-Type, Accept, Authorization
|
||
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
|
||
Access-Control-Max-Age: 86400
|
||
```
|
||
|
||
---
|
||
|
||
## 🔒 Güvenlik Notları
|
||
|
||
### Whitelist Best Practices:
|
||
|
||
✅ **Yapın:**
|
||
- Sadece güvendiğiniz domain'leri ekleyin
|
||
- Her environment için ayrı origin kullanın
|
||
- HTTPS kullanın (production için)
|
||
- Description field'ını doldurun
|
||
|
||
❌ **Yapmayın:**
|
||
- Wildcard (`*`) kullanmayın
|
||
- HTTP kullanmayın (production'da)
|
||
- Herkese açık domain eklemeyin
|
||
- Test domain'lerini production'da bırakmayın
|
||
|
||
### Blacklist Kullanımı:
|
||
|
||
Şüpheli veya kötü niyetli origin'leri blacklist'e ekleyin:
|
||
|
||
```bash
|
||
curl -X POST https://goauth.beyhano.net.tr/v1/settings/cors/blacklist \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"origin": "https://malicious-site.com",
|
||
"reason": "Security threat detected"
|
||
}'
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 Troubleshooting
|
||
|
||
### Hala 403 alıyorsanız:
|
||
|
||
1. **Whitelist'te var mı kontrol edin:**
|
||
```bash
|
||
curl -X GET https://goauth.beyhano.net.tr/v1/settings/cors/whitelist \
|
||
-H "Authorization: Bearer $TOKEN" | jq '.[] | .origin'
|
||
```
|
||
|
||
2. **Origin tam eşleşiyor mu?**
|
||
- ✅ `https://nextgo.beyhano.net.tr` (doğru)
|
||
- ❌ `https://nextgo.beyhano.net.tr/` (slash yanlış)
|
||
- ❌ `http://nextgo.beyhano.net.tr` (http/https farkı)
|
||
|
||
3. **is_active = true mi?**
|
||
```bash
|
||
curl -X GET https://goauth.beyhano.net.tr/v1/settings/cors/whitelist \
|
||
-H "Authorization: Bearer $TOKEN" | jq '.[] | {origin, is_active}'
|
||
```
|
||
|
||
4. **Redis cache'i temizleyin:**
|
||
```bash
|
||
docker exec -it gauth_redis redis-cli
|
||
> DEL cors:whitelist
|
||
> DEL cors:blacklist
|
||
> exit
|
||
```
|
||
|
||
5. **Container'ı restart edin:**
|
||
```bash
|
||
docker restart app_auth_central
|
||
```
|
||
|
||
---
|
||
|
||
## 📖 İlgili Dokümantasyon
|
||
|
||
- **CORS API Detayları:** `CORS_API_DOCUMENTATION.md`
|
||
- **Test Script:** `test-cors-api.sh`
|
||
- **Deployment Guide:** `DOKPLOY_DEPLOYMENT.md`
|
||
|
||
---
|
||
|
||
## ✅ Checklist
|
||
|
||
Production'a geçmeden önce:
|
||
|
||
- [ ] Admin kullanıcı oluşturuldu
|
||
- [ ] Production frontend origin whitelist'e eklendi
|
||
- [ ] Development origin whitelist'e eklendi (opsiyonel)
|
||
- [ ] Whitelist doğrulandı (GET request)
|
||
- [ ] Frontend'den test edildi
|
||
- [ ] OPTIONS preflight request test edildi
|
||
- [ ] Browser console'da CORS hatası yok
|
||
- [ ] Redis cache çalışıyor
|
||
- [ ] Swagger'da CORS endpoints görünüyor
|
||
|
||
**CORS 403 hatası çözüldü!** ✅
|