Protects image upload, delete, and tag-update endpoints behind Bearer token auth. Public read endpoints remain open. Angular SPA gains a login page, auth interceptor, and route guard for /upload. - JWTAuthProvider (HS256, sub/iat/exp, secrets.compare_digest) - POST /api/v1/auth/token login endpoint - require_auth FastAPI dependency on all write routes - AuthService, LoginComponent, authInterceptor, authGuard - Detail page hides write controls for unauthenticated visitors - 43 unit tests passing; integration tests require Docker stack Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
52 lines
1.6 KiB
Python
52 lines
1.6 KiB
Python
import pytest
|
|
|
|
_VALID_CREDS = {"username": "testowner", "password": "testpassword"}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_login_success(authed_client):
|
|
client, _ = authed_client
|
|
response = await client.post("/api/v1/auth/token", json=_VALID_CREDS)
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert isinstance(body.get("access_token"), str)
|
|
assert len(body["access_token"]) > 0
|
|
assert body.get("token_type") == "bearer"
|
|
assert body.get("expires_in", 0) > 0
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_login_wrong_password(authed_client):
|
|
client, _ = authed_client
|
|
response = await client.post(
|
|
"/api/v1/auth/token",
|
|
json={"username": "testowner", "password": "wrongpassword"},
|
|
)
|
|
assert response.status_code == 401
|
|
assert response.json().get("code") == "invalid_credentials"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_login_wrong_username(authed_client):
|
|
client, _ = authed_client
|
|
response = await client.post(
|
|
"/api/v1/auth/token",
|
|
json={"username": "notowner", "password": "testpassword"},
|
|
)
|
|
assert response.status_code == 401
|
|
assert response.json().get("code") == "invalid_credentials"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_login_missing_password(authed_client):
|
|
client, _ = authed_client
|
|
response = await client.post("/api/v1/auth/token", json={"username": "testowner"})
|
|
assert response.status_code == 422
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_login_missing_username(authed_client):
|
|
client, _ = authed_client
|
|
response = await client.post("/api/v1/auth/token", json={"password": "testpassword"})
|
|
assert response.status_code == 422
|