Fixed login redirecting issues

This commit is contained in:
2025-11-21 23:38:03 +01:00
parent 2532a977c1
commit 608fa8b95c
5 changed files with 402 additions and 23 deletions

View File

@@ -506,6 +506,172 @@ current_customer: Customer = Depends(get_current_customer_api)
current_user: User = Depends(get_current_user)
```
---
### Optional Authentication Dependencies
These dependencies return `None` instead of raising exceptions when authentication fails. Used for login pages and public routes that need to conditionally check if a user is authenticated.
#### `get_current_admin_optional()`
**Purpose:** Check if admin user is authenticated (without enforcing)
**Accepts:** Cookie (`admin_token`) OR Authorization header
**Returns:**
- `User` object with `role="admin"` if authenticated
- `None` if no token, invalid token, or user is not admin
**Raises:** Never raises exceptions
**Usage:**
```python
# Login page redirect
@router.get("/admin/login")
async def admin_login_page(
request: Request,
current_user: Optional[User] = Depends(get_current_admin_optional)
):
if current_user:
# User already logged in, redirect to dashboard
return RedirectResponse(url="/admin/dashboard", status_code=302)
# Not logged in, show login form
return templates.TemplateResponse("admin/login.html", {"request": request})
```
**Use Cases:**
- Login pages (redirect if already authenticated)
- Public pages with conditional admin content
- Root redirects based on authentication status
#### `get_current_vendor_optional()`
**Purpose:** Check if vendor user is authenticated (without enforcing)
**Accepts:** Cookie (`vendor_token`) OR Authorization header
**Returns:**
- `User` object with `role="vendor"` if authenticated
- `None` if no token, invalid token, or user is not vendor
**Raises:** Never raises exceptions
**Usage:**
```python
# Login page redirect
@router.get("/vendor/{vendor_code}/login")
async def vendor_login_page(
request: Request,
vendor_code: str = Path(...),
current_user: Optional[User] = Depends(get_current_vendor_optional)
):
if current_user:
# User already logged in, redirect to dashboard
return RedirectResponse(url=f"/vendor/{vendor_code}/dashboard", status_code=302)
# Not logged in, show login form
return templates.TemplateResponse("vendor/login.html", {
"request": request,
"vendor_code": vendor_code
})
```
**Use Cases:**
- Login pages (redirect if already authenticated)
- Public vendor pages with conditional content
- Root redirects based on authentication status
#### `get_current_customer_optional()`
**Purpose:** Check if customer user is authenticated (without enforcing)
**Accepts:** Cookie (`customer_token`) OR Authorization header
**Returns:**
- `User` object with `role="customer"` if authenticated
- `None` if no token, invalid token, or user is not customer
**Raises:** Never raises exceptions
**Usage:**
```python
# Shop login page redirect
@router.get("/shop/account/login")
async def customer_login_page(
request: Request,
current_user: Optional[User] = Depends(get_current_customer_optional)
):
if current_user:
# User already logged in, redirect to account page
return RedirectResponse(url="/shop/account", status_code=302)
# Not logged in, show login form
return templates.TemplateResponse("shop/login.html", {"request": request})
```
**Use Cases:**
- Login pages (redirect if already authenticated)
- Public shop pages with conditional customer content (e.g., "My Orders" link)
- Root redirects based on authentication status
---
### Required vs Optional Dependencies
Understanding when to use each type:
#### Admin Context
| Scenario | Use | Returns | On Auth Failure |
|----------|-----|---------|-----------------|
| **Protected page (dashboard, settings)** | `get_current_admin_from_cookie_or_header` | `User` | Raises 401 exception |
| **Login page** | `get_current_admin_optional` | `Optional[User]` | Returns `None` |
| **API endpoint** | `get_current_admin_api` | `User` | Raises 401 exception |
| **Public page with conditional content** | `get_current_admin_optional` | `Optional[User]` | Returns `None` |
#### Vendor Context
| Scenario | Use | Returns | On Auth Failure |
|----------|-----|---------|-----------------|
| **Protected page (dashboard, products)** | `get_current_vendor_from_cookie_or_header` | `User` | Raises 401 exception |
| **Login page** | `get_current_vendor_optional` | `Optional[User]` | Returns `None` |
| **API endpoint** | `get_current_vendor_api` | `User` | Raises 401 exception |
| **Public page with conditional content** | `get_current_vendor_optional` | `Optional[User]` | Returns `None` |
#### Customer Context
| Scenario | Use | Returns | On Auth Failure |
|----------|-----|---------|-----------------|
| **Protected page (account, orders)** | `get_current_customer_from_cookie_or_header` | `User` | Raises 401 exception |
| **Login page** | `get_current_customer_optional` | `Optional[User]` | Returns `None` |
| **API endpoint** | `get_current_customer_api` | `User` | Raises 401 exception |
| **Public page with conditional content** | `get_current_customer_optional` | `Optional[User]` | Returns `None` |
**Example Flow:**
```python
# ❌ WRONG: Using required auth on login page
@router.get("/admin/login")
async def admin_login_page(
current_user: User = Depends(get_current_admin_from_cookie_or_header)
):
# This will return 401 error if not logged in!
# Login page will never render for unauthenticated users
...
# ✅ CORRECT: Using optional auth on login page
@router.get("/admin/login")
async def admin_login_page(
current_user: Optional[User] = Depends(get_current_admin_optional)
):
# Returns None if not logged in, page renders normally
if current_user:
return RedirectResponse(url="/admin/dashboard")
return templates.TemplateResponse("login.html", ...)
# ✅ CORRECT: Using required auth on protected page
@router.get("/admin/dashboard")
async def admin_dashboard(
current_user: User = Depends(get_current_admin_from_cookie_or_header)
):
# Automatically returns 401 if not authenticated
# Only runs if user is authenticated admin
...
```
### Login Response Format
All login endpoints return: