Files
Frontend/AUTH_API.md
2026-03-24 13:53:21 +03:30

433 lines
11 KiB
Markdown

# Authentication & Account API Documentation
## فهرست مطالب
- [مکانیزم احراز هویت](#مکانیزم-احراز-هویت)
- [فرمت کلی پاسخ‌ها](#فرمت-کلی-پاسخها)
- [مدل کاربر](#مدل-کاربر)
- [Auth Endpoints](#auth-endpoints)
- [ثبت‌نام](#1-ثبت‌نام)
- [ورود با رمز عبور](#2-ورود-با-رمز-عبور)
- [درخواست OTP](#3-درخواست-otp)
- [تأیید OTP](#4-تأیید-otp)
- [رفرش توکن](#5-رفرش-توکن)
- [Account Endpoints](#account-endpoints)
- [آپدیت پروفایل](#1-آپدیت-پروفایل)
- [احراز هویت در درخواست‌ها](#احراز-هویت-در-درخواستها)
- [کدهای خطا](#کدهای-خطا)
---
## مکانیزم احراز هویت
پروژه از **JWT (JSON Web Token)** با کتابخانه `djangorestframework-simplejwt` استفاده می‌کند.
- هر بار که کاربر ثبت‌نام یا لاگین موفق انجام می‌دهد، دو توکن دریافت می‌کند:
- **`access`** — توکن کوتاه‌مدت برای احراز هویت درخواست‌ها
- **`refresh`** — توکن بلندمدت برای گرفتن `access` جدید
- برای اندپوینت‌هایی که نیاز به احراز هویت دارند، باید توکن `access` را در هدر `Authorization` ارسال کنید:
```
Authorization: Bearer <access_token>
```
- Backend احراز هویت: `MultiFieldBackend` — کاربر می‌تواند با `username`، `email` یا `phone_number` لاگین کند.
---
## فرمت کلی پاسخ‌ها
همه پاسخ‌ها از یک ساختار یکسان پیروی می‌کنند:
```json
{
"code": 200,
"msg": "success",
"data": { ... }
}
```
| فیلد | نوع | توضیح |
|---------|---------|---------------------------------------------|
| `code` | integer | کد وضعیت (مشابه HTTP status) |
| `msg` | string | پیام وضعیت (`"success"` یا متن خطا) |
| `data` | object | داده‌های برگشتی (در صورت وجود) |
| `token` | object | توکن‌های JWT (فقط در پاسخ‌های auth) |
---
## مدل کاربر
شیء `AuthUser` که در پاسخ‌های احراز هویت و پروفایل برگردانده می‌شود:
```json
{
"id": 1,
"username": "john_doe",
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe",
"phone_number": "09121234567"
}
```
---
## Auth Endpoints
Base URL: `/api/auth/`
---
### 1. ثبت‌نام
**`POST /api/auth/register/`**
ساخت حساب کاربری جدید با نام کاربری، ایمیل، شماره موبایل و رمز عبور.
#### Request Body
```json
{
"username": "john_doe",
"email": "john@example.com",
"phone_number": "09121234567",
"password": "securepass123",
"first_name": "John",
"last_name": "Doe"
}
```
| فیلد | نوع | الزامی | توضیح |
|----------------|--------|--------|-------------------------------|
| `username` | string | ✅ | حداکثر ۱۵۰ کاراکتر، یکتا |
| `email` | string | ✅ | فرمت ایمیل، یکتا |
| `phone_number` | string | ✅ | حداکثر ۳۲ کاراکتر، یکتا |
| `password` | string | ✅ | حداقل ۸ کاراکتر |
| `first_name` | string | ❌ | حداکثر ۱۵۰ کاراکتر |
| `last_name` | string | ❌ | حداکثر ۱۵۰ کاراکتر |
#### Response موفق — `201 Created`
```json
{
"code": 201,
"msg": "success",
"data": {
"id": 1,
"username": "john_doe",
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe",
"phone_number": "09121234567"
},
"token": {
"access": "<access_token>",
"refresh": "<refresh_token>"
}
}
```
#### Response خطا — `400 Bad Request`
```json
{
"code": 400,
"msg": "A user with this username already exists."
}
```
پیام‌های خطای احتمالی:
- `"A user with this username already exists."`
- `"A user with this email already exists."`
- `"A user with this phone number already exists."`
- `"A user with these credentials already exists."`
---
### 2. ورود با رمز عبور
**`POST /api/auth/login/`**
ورود با استفاده از `username`، `email` یا `phone_number` به همراه رمز عبور.
#### Request Body
```json
{
"identifier": "john_doe",
"password": "securepass123"
}
```
| فیلد | نوع | الزامی | توضیح |
|--------------|--------|--------|-----------------------------------------------------|
| `identifier` | string | ✅ | می‌تواند `username`، `email` یا `phone_number` باشد |
| `password` | string | ✅ | رمز عبور کاربر |
#### Response موفق — `200 OK`
```json
{
"code": 200,
"msg": "success",
"data": {
"id": 1,
"username": "john_doe",
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe",
"phone_number": "09121234567"
},
"token": {
"access": "<access_token>",
"refresh": "<refresh_token>"
}
}
```
#### Response خطا — `401 Unauthorized`
```json
{
"code": 401,
"msg": "Invalid credentials."
}
```
---
### 3. درخواست OTP
**`POST /api/auth/request-otp/`**
> ⚠️ این endpoint در حال حاضر در `urls.py` کامنت شده است (غیرفعال).
ارسال کد یکبار مصرف (OTP) به شماره موبایل از طریق SMS.ir.
#### Request Body
```json
{
"phone_number": "09121234567"
}
```
| فیلد | نوع | الزامی | توضیح |
|----------------|--------|--------|---------------------|
| `phone_number` | string | ✅ | حداکثر ۳۲ کاراکتر |
#### Response موفق — `200 OK`
```json
{
"code": 200,
"msg": "success",
"token": "<otp_token>"
}
```
| فیلد | توضیح |
|---------------|--------------------------------------------------------------|
| `token` | توکن امضاشده که باید در مرحله verify-otp ارسال شود |
| `sms_warning` | (اختیاری) در صورت شکست ارسال پیامک ظاهر می‌شود |
| `debug_otp` | (اختیاری) فقط در حالت `DEBUG=True` — کد OTP در پاسخ می‌آید |
> کد OTP مدت اعتبار **۳۰۰ ثانیه (۵ دقیقه)** دارد.
---
### 4. تأیید OTP
**`POST /api/auth/verify-otp/`**
> ⚠️ این endpoint در حال حاضر در `urls.py` کامنت شده است (غیرفعال).
تأیید کد OTP دریافت‌شده و ورود/ثبت‌نام خودکار کاربر.
#### Request Body
```json
{
"token": "<otp_token>",
"otp_code": "123456"
}
```
| فیلد | نوع | الزامی | توضیح |
|------------|--------|--------|-------------------------------------------|
| `token` | string | ✅ | توکن دریافت‌شده از مرحله request-otp |
| `otp_code` | string | ✅ | کد ۶ رقمی ارسال‌شده به موبایل |
#### Response موفق — `200 OK`
```json
{
"code": 200,
"msg": "success",
"data": {
"id": 1,
"username": "09121234567",
"email": "09121234567@otp.local",
"first_name": "",
"last_name": "",
"phone_number": "09121234567"
},
"token": {
"access": "<access_token>",
"refresh": "<refresh_token>"
}
}
```
> اگر کاربر با این شماره موبایل قبلاً ثبت‌نام نکرده باشد، حساب جدید به‌صورت خودکار ساخته می‌شود.
#### Response خطا — `400 Bad Request`
```json
{
"code": 400,
"msg": "Token is invalid or expired."
}
```
یا:
```json
{
"code": 400,
"msg": "OTP code is invalid or expired."
}
```
---
### 5. رفرش توکن
**`POST /api/auth/token/refresh/`**
دریافت `access` token جدید با استفاده از `refresh` token.
> این endpoint توسط `djangorestframework-simplejwt` به‌صورت پیش‌فرض فراهم می‌شود.
#### Request Body
```json
{
"refresh": "<refresh_token>"
}
```
#### Response موفق — `200 OK`
```json
{
"access": "<new_access_token>"
}
```
---
## Account Endpoints
Base URL: `/api/account/`
---
### 1. آپدیت پروفایل
**`PATCH /api/account/profile/`**
> 🔒 نیاز به احراز هویت دارد — هدر `Authorization: Bearer <access_token>` الزامی است.
ویرایش اطلاعات پروفایل کاربر لاگین‌شده.
#### Request Body
همه فیلدها اختیاری هستند (partial update):
```json
{
"first_name": "علی",
"last_name": "احمدی",
"email": "new_email@example.com"
}
```
| فیلد | نوع | الزامی | توضیح |
|--------------|--------|--------|---------------------|
| `first_name` | string | ❌ | حداکثر ۱۵۰ کاراکتر |
| `last_name` | string | ❌ | حداکثر ۱۵۰ کاراکتر |
| `email` | string | ❌ | فرمت ایمیل معتبر |
#### Response موفق — `200 OK`
```json
{
"code": 200,
"msg": "success",
"data": {
"id": 1,
"username": "john_doe",
"email": "new_email@example.com",
"first_name": "علی",
"last_name": "احمدی",
"phone_number": "09121234567"
}
}
```
#### Response خطا — `401 Unauthorized`
در صورت نبود یا منقضی بودن توکن:
```json
{
"detail": "Authentication credentials were not provided."
}
```
---
## احراز هویت در درخواست‌ها
برای اندپوینت‌هایی که نیاز به احراز هویت دارند (مانند `PATCH /api/account/profile/`)، توکن `access` را در هدر HTTP ارسال کنید:
```
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
### چرخه عمر توکن
```
[ثبت‌نام / لاگین]
دریافت access + refresh
ارسال درخواست‌ها با access
منقضی شدن access (401)
ارسال refresh به POST /api/auth/token/refresh/
دریافت access جدید
```
---
## کدهای خطا
| HTTP Status | code | معنا |
|-------------|------|-----------------------------------------------|
| 201 | 201 | ثبت‌نام موفق |
| 200 | 200 | عملیات موفق |
| 400 | 400 | داده‌های نامعتبر یا OTP/توکن اشتباه |
| 401 | 401 | احراز هویت ناموفق (رمز اشتباه یا بدون توکن) |
> پاسخ‌های خطای اعتبارسنجی serializer (مانند فیلد اجباری) با فرمت استاندارد DRF برگردانده می‌شوند:
> ```json
> {
> "field_name": ["This field is required."]
> }
> ```