587 lines
14 KiB
Markdown
587 lines
14 KiB
Markdown
# Kullanıcı Profil Yönetimi API
|
||
|
||
## Genel Bakış
|
||
|
||
AuthCentral kullanıcıları kendi profillerini yönetebilir. Bu dokümantasyon kullanıcı profil yönetimi endpoint'lerini açıklar.
|
||
|
||
## Endpoint'ler
|
||
|
||
### 1. Profil Bilgilerini Getir
|
||
|
||
```bash
|
||
GET /v1/profile
|
||
```
|
||
|
||
**Headers:**
|
||
- `Authorization: Bearer {access_token}`
|
||
|
||
**Yanıt:**
|
||
```json
|
||
{
|
||
"id": "7d8b023c-d5e4-4f62-8811-ddbf00d675bb",
|
||
"username": "admin",
|
||
"email": "admin@gauth.local",
|
||
"avatar": "/uploads/avatars/admin_avatar.png",
|
||
"email_verified": true,
|
||
"is_oauth_user": false,
|
||
"created_at": "2026-02-04T20:00:00Z",
|
||
"updated_at": "2026-02-05T10:00:00Z",
|
||
"roles": [
|
||
{
|
||
"id": 1,
|
||
"name": "admin",
|
||
"description": "Administrator role"
|
||
}
|
||
],
|
||
"social_accounts": []
|
||
}
|
||
```
|
||
|
||
**Yeni Field:**
|
||
- `is_oauth_user` (boolean) - Kullanıcı OAuth ile mi giriş yapmış (Google/GitHub)
|
||
|
||
**Örnek:**
|
||
```bash
|
||
TOKEN="your_access_token_here"
|
||
|
||
curl -X GET "http://localhost:8080/v1/profile" \
|
||
-H "Authorization: Bearer $TOKEN"
|
||
```
|
||
|
||
---
|
||
|
||
### 2. Profil Güncelle
|
||
|
||
```bash
|
||
PUT /v1/profile
|
||
```
|
||
|
||
**Headers:**
|
||
- `Authorization: Bearer {access_token}`
|
||
- `Content-Type: multipart/form-data` (avatar yüklemek için)
|
||
|
||
**Form Data:**
|
||
- `user_name` (string, optional) - Yeni kullanıcı adı
|
||
- `avatar` (file, optional) - Profil resmi (max 5MB)
|
||
|
||
**Örnek (Username Güncelleme):**
|
||
```bash
|
||
TOKEN="your_access_token_here"
|
||
|
||
curl -X PUT "http://localhost:8080/v1/profile" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-F "user_name=Beyhan Oğur"
|
||
```
|
||
|
||
**Örnek (Avatar Yükleme):**
|
||
```bash
|
||
TOKEN="your_access_token_here"
|
||
|
||
curl -X PUT "http://localhost:8080/v1/profile" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-F "avatar=@/path/to/profile-picture.jpg"
|
||
```
|
||
|
||
**Örnek (Username + Avatar):**
|
||
```bash
|
||
TOKEN="your_access_token_here"
|
||
|
||
curl -X PUT "http://localhost:8080/v1/profile" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-F "user_name=Beyhan Oğur" \
|
||
-F "avatar=@/path/to/profile-picture.jpg"
|
||
```
|
||
|
||
**Başarılı Yanıt:**
|
||
```json
|
||
{
|
||
"message": "Profile updated successfully",
|
||
"user": {
|
||
"id": "7d8b023c-d5e4-4f62-8811-ddbf00d675bb",
|
||
"username": "Beyhan Oğur",
|
||
"email": "admin@gauth.local",
|
||
"avatar": "/uploads/avatars/7d8b023c_1770238858420987000.png",
|
||
"email_verified": true,
|
||
"roles": [...]
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3. Şifre Değiştir
|
||
|
||
```bash
|
||
PUT /v1/profile/password
|
||
```
|
||
|
||
**Headers:**
|
||
- `Authorization: Bearer {access_token}`
|
||
- `Content-Type: application/json`
|
||
|
||
**Request Body:**
|
||
```json
|
||
{
|
||
"current_password": "OldPassword123",
|
||
"new_password": "NewPassword123"
|
||
}
|
||
```
|
||
|
||
**Örnek:**
|
||
```bash
|
||
TOKEN="your_access_token_here"
|
||
|
||
curl -X PUT "http://localhost:8080/v1/profile/password" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"current_password": "OldPassword123",
|
||
"new_password": "NewPassword123"
|
||
}'
|
||
```
|
||
|
||
**Başarılı Yanıt:**
|
||
```json
|
||
{
|
||
"message": "Password changed successfully"
|
||
}
|
||
```
|
||
|
||
**Hata Yanıtları:**
|
||
```json
|
||
{
|
||
"error": "Current password is incorrect"
|
||
}
|
||
```
|
||
|
||
```json
|
||
{
|
||
"error": "Cannot change password for OAuth users (Google/GitHub login)"
|
||
}
|
||
```
|
||
|
||
**Notlar:**
|
||
- ✅ Mevcut şifre doğrulanır
|
||
- ✅ Yeni şifre minimum 6 karakter olmalı
|
||
- ⚠️ **OAuth kullanıcıları (Google/GitHub) şifre değiştiremez**
|
||
- ⚠️ Şifre değiştirildikten sonra yeni şifre ile login yapılmalı
|
||
- 💡 `is_oauth_user: true` ise şifre değiştirme butonu gösterilmemeli
|
||
|
||
---
|
||
|
||
### 4. Email Adresi Değiştir
|
||
|
||
```bash
|
||
PUT /v1/profile/email
|
||
```
|
||
|
||
**Headers:**
|
||
- `Authorization: Bearer {access_token}`
|
||
- `Content-Type: application/json`
|
||
|
||
**Request Body:**
|
||
```json
|
||
{
|
||
"new_email": "newemail@example.com",
|
||
"password": "YourCurrentPassword"
|
||
}
|
||
```
|
||
|
||
**Örnek:**
|
||
```bash
|
||
TOKEN="your_access_token_here"
|
||
|
||
curl -X PUT "http://localhost:8080/v1/profile/email" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"new_email": "newemail@example.com",
|
||
"password": "YourPassword123"
|
||
}'
|
||
```
|
||
|
||
**Başarılı Yanıt:**
|
||
```json
|
||
{
|
||
"message": "Email updated. Please verify your new email address.",
|
||
"new_email": "newemail@example.com",
|
||
"verification_token": "abc123def456..."
|
||
}
|
||
```
|
||
|
||
**Hata Yanıtları:**
|
||
```json
|
||
{
|
||
"error": "Password is incorrect"
|
||
}
|
||
```
|
||
|
||
```json
|
||
{
|
||
"error": "Email already in use"
|
||
}
|
||
```
|
||
|
||
```json
|
||
{
|
||
"error": "Cannot change email for OAuth users (Google/GitHub login)"
|
||
}
|
||
```
|
||
|
||
**Önemli Notlar:**
|
||
- ⚠️ **OAuth kullanıcıları (Google/GitHub) email değiştiremez**
|
||
- ⚠️ Email değiştirildiğinde `email_verified` false olur
|
||
- ⚠️ Yeni email adresine doğrulama email'i gönderilir
|
||
- ⚠️ Email doğrulanana kadar login yapılamaz
|
||
- ⚠️ Email doğrulama için `/v1/auth/verify-email?token=...` endpoint'i kullanılır
|
||
- 💡 `is_oauth_user: true` ise email değiştirme butonu gösterilmemeli
|
||
|
||
---
|
||
|
||
## Kullanım Senaryoları
|
||
|
||
### Senaryo 1: Tam Profil Güncelleme
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
|
||
# Login
|
||
TOKEN=$(curl -s -X POST http://localhost:8080/v1/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"email":"user@example.com","password":"password123"}' | jq -r '.access_token')
|
||
|
||
# 1. Kullanıcı adını güncelle
|
||
curl -X PUT "http://localhost:8080/v1/profile" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-F "user_name=Yeni İsim"
|
||
|
||
# 2. Avatar yükle
|
||
curl -X PUT "http://localhost:8080/v1/profile" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-F "avatar=@./my-photo.jpg"
|
||
|
||
# 3. Şifre değiştir
|
||
curl -X PUT "http://localhost:8080/v1/profile/password" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"current_password": "password123",
|
||
"new_password": "newpassword456"
|
||
}'
|
||
|
||
# 4. Profili kontrol et
|
||
curl -X GET "http://localhost:8080/v1/profile" \
|
||
-H "Authorization: Bearer $TOKEN" | jq '.'
|
||
```
|
||
|
||
### Senaryo 2: Email Değiştirme ve Doğrulama
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
|
||
# Login
|
||
TOKEN=$(curl -s -X POST http://localhost:8080/v1/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"email":"old@example.com","password":"password123"}' | jq -r '.access_token')
|
||
|
||
# 1. Email değiştir
|
||
RESPONSE=$(curl -s -X PUT "http://localhost:8080/v1/profile/email" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"new_email": "new@example.com",
|
||
"password": "password123"
|
||
}')
|
||
|
||
echo $RESPONSE | jq '.'
|
||
|
||
# 2. Verification token'ı al
|
||
VERIFY_TOKEN=$(echo $RESPONSE | jq -r '.verification_token')
|
||
|
||
# 3. Email'i doğrula
|
||
curl -X GET "http://localhost:8080/v1/auth/verify-email?token=$VERIFY_TOKEN"
|
||
|
||
# 4. Yeni email ile login
|
||
curl -X POST http://localhost:8080/v1/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"email": "new@example.com",
|
||
"password": "password123"
|
||
}'
|
||
```
|
||
|
||
---
|
||
|
||
## Frontend Entegrasyonu
|
||
|
||
### React Örneği
|
||
|
||
```jsx
|
||
import React, { useState, useEffect } from 'react';
|
||
|
||
function ProfilePage() {
|
||
const [user, setUser] = useState(null);
|
||
const [loading, setLoading] = useState(false);
|
||
const token = localStorage.getItem('access_token');
|
||
|
||
// Profil bilgilerini yükle
|
||
const fetchProfile = async () => {
|
||
try {
|
||
const response = await fetch('http://localhost:8080/v1/profile', {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
}
|
||
});
|
||
const data = await response.json();
|
||
setUser(data);
|
||
} catch (error) {
|
||
console.error('Error fetching profile:', error);
|
||
}
|
||
};
|
||
|
||
// Username güncelle
|
||
const updateUsername = async (newUsername) => {
|
||
const formData = new FormData();
|
||
formData.append('user_name', newUsername);
|
||
|
||
try {
|
||
const response = await fetch('http://localhost:8080/v1/profile', {
|
||
method: 'PUT',
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
},
|
||
body: formData
|
||
});
|
||
|
||
if (response.ok) {
|
||
fetchProfile(); // Profili yenile
|
||
alert('Username updated!');
|
||
}
|
||
} catch (error) {
|
||
console.error('Error updating username:', error);
|
||
}
|
||
};
|
||
|
||
// Avatar yükle
|
||
const uploadAvatar = async (file) => {
|
||
const formData = new FormData();
|
||
formData.append('avatar', file);
|
||
|
||
try {
|
||
const response = await fetch('http://localhost:8080/v1/profile', {
|
||
method: 'PUT',
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
},
|
||
body: formData
|
||
});
|
||
|
||
if (response.ok) {
|
||
fetchProfile(); // Profili yenile
|
||
alert('Avatar uploaded!');
|
||
}
|
||
} catch (error) {
|
||
console.error('Error uploading avatar:', error);
|
||
}
|
||
};
|
||
|
||
// Şifre değiştir
|
||
const changePassword = async (currentPassword, newPassword) => {
|
||
try {
|
||
const response = await fetch('http://localhost:8080/v1/profile/password', {
|
||
method: 'PUT',
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`,
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
current_password: currentPassword,
|
||
new_password: newPassword
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (response.ok) {
|
||
alert('Password changed successfully!');
|
||
} else {
|
||
alert(data.error);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error changing password:', error);
|
||
}
|
||
};
|
||
|
||
// Email değiştir
|
||
const changeEmail = async (newEmail, password) => {
|
||
try {
|
||
const response = await fetch('http://localhost:8080/v1/profile/email', {
|
||
method: 'PUT',
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`,
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
new_email: newEmail,
|
||
password: password
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (response.ok) {
|
||
alert('Email updated! Please check your email to verify.');
|
||
} else {
|
||
alert(data.error);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error changing email:', error);
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
fetchProfile();
|
||
}, []);
|
||
|
||
return (
|
||
<div>
|
||
<h1>Profile</h1>
|
||
{user && (
|
||
<div>
|
||
<img src={`http://localhost:8080${user.avatar}`} alt="Avatar" />
|
||
<p>Username: {user.username}</p>
|
||
<p>Email: {user.email}</p>
|
||
<p>Verified: {user.email_verified ? 'Yes' : 'No'}</p>
|
||
|
||
{/* OAuth user indicator */}
|
||
{user.is_oauth_user && (
|
||
<p className="info">
|
||
ℹ️ Logged in with {user.social_accounts?.[0]?.provider || 'OAuth'}
|
||
</p>
|
||
)}
|
||
|
||
{/* Password change - only for non-OAuth users */}
|
||
{!user.is_oauth_user && (
|
||
<button onClick={() => {
|
||
const current = prompt('Current password:');
|
||
const newPass = prompt('New password:');
|
||
if (current && newPass) changePassword(current, newPass);
|
||
}}>
|
||
Change Password
|
||
</button>
|
||
)}
|
||
|
||
{/* Email change - only for non-OAuth users */}
|
||
{!user.is_oauth_user && (
|
||
<button onClick={() => {
|
||
const newEmail = prompt('New email:');
|
||
const password = prompt('Your password:');
|
||
if (newEmail && password) changeEmail(newEmail, password);
|
||
}}>
|
||
Change Email
|
||
</button>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## API Özeti
|
||
|
||
| Endpoint | Method | Açıklama | Auth Required |
|
||
|----------|--------|----------|---------------|
|
||
| `/v1/profile` | GET | Profil bilgilerini getir | ✅ |
|
||
| `/v1/profile` | PUT | Profil güncelle (username, avatar) | ✅ |
|
||
| `/v1/profile/password` | PUT | Şifre değiştir | ✅ |
|
||
| `/v1/profile/email` | PUT | Email değiştir | ✅ |
|
||
|
||
---
|
||
|
||
## Güvenlik Notları
|
||
|
||
✅ **İyi Pratikler:**
|
||
- Şifre değiştirirken mevcut şifre doğrulanır
|
||
- Email değiştirirken doğrulama email'i gönderilir
|
||
- Avatar dosya boyutu sınırlandırılmıştır (max 5MB)
|
||
- Tüm endpoint'ler authentication gerektirir
|
||
|
||
⚠️ **Dikkat Edilmesi Gerekenler:**
|
||
- **OAuth kullanıcıları (Google/GitHub) şifre ve email değiştiremez**
|
||
- OAuth kullanıcıları sadece username ve avatar değiştirebilir
|
||
- Frontend'de `is_oauth_user` flag'ini kontrol edin
|
||
- Şifre değiştirme butonu OAuth kullanıcılarına gösterilmemeli
|
||
- Email değiştirme butonu OAuth kullanıcılarına gösterilmemeli
|
||
- Email değiştirildiğinde yeniden doğrulama gerekir
|
||
- Şifre minimum 6 karakter olmalı
|
||
- Avatar sadece resim formatları kabul edilir
|
||
|
||
## OAuth Kullanıcı Kısıtlamaları
|
||
|
||
| Özellik | Email/Password Kullanıcı | OAuth Kullanıcı (Google/GitHub) |
|
||
|---------|-------------------------|--------------------------------|
|
||
| Profil Görüntüleme | ✅ Evet | ✅ Evet |
|
||
| Username Değiştirme | ✅ Evet | ✅ Evet |
|
||
| Avatar Yükleme | ✅ Evet | ✅ Evet |
|
||
| **Şifre Değiştirme** | ✅ Evet | ❌ **Hayır** |
|
||
| **Email Değiştirme** | ✅ Evet | ❌ **Hayır** |
|
||
|
||
**Önemli:** Frontend'de `is_oauth_user` field'ını kontrol ederek UI'ı buna göre düzenleyin.
|
||
|
||
---
|
||
|
||
## Test Komutları
|
||
|
||
```bash
|
||
# Login ve token al
|
||
TOKEN=$(curl -s -X POST http://localhost:8080/v1/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"email":"user@example.com","password":"password123"}' | jq -r '.access_token')
|
||
|
||
# Profil bilgilerini getir
|
||
curl -X GET "http://localhost:8080/v1/profile" \
|
||
-H "Authorization: Bearer $TOKEN" | jq '.'
|
||
|
||
# Username güncelle
|
||
curl -X PUT "http://localhost:8080/v1/profile" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-F "user_name=New Name"
|
||
|
||
# Avatar yükle
|
||
curl -X PUT "http://localhost:8080/v1/profile" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-F "avatar=@./photo.jpg"
|
||
|
||
# Şifre değiştir
|
||
curl -X PUT "http://localhost:8080/v1/profile/password" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"current_password":"old123","new_password":"new456"}'
|
||
|
||
# Email değiştir
|
||
curl -X PUT "http://localhost:8080/v1/profile/email" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"new_email":"new@email.com","password":"password123"}'
|
||
```
|
||
|
||
---
|
||
|
||
## Özet
|
||
|
||
🎯 **Özellikler:**
|
||
- ✅ Profil bilgilerini görüntüleme
|
||
- ✅ Kullanıcı adı güncelleme
|
||
- ✅ Avatar yükleme (max 5MB)
|
||
- ✅ Şifre değiştirme (mevcut şifre doğrulaması ile)
|
||
- ✅ Email değiştirme (yeniden doğrulama ile)
|
||
|
||
📊 **Kullanım:**
|
||
- Her kullanıcı kendi profilini yönetebilir
|
||
- OAuth kullanıcıları şifre değiştiremez
|
||
- Email değişikliği doğrulama gerektirir
|
||
- Avatar otomatik optimize edilir
|