fix(markdown): img auth via ?token= query param (Authorization header 미지원)
`<img src=>` 가 Authorization header 를 못 보내서 /api/documents/{id}/images/{key}/raw
가 401 반환 → 이미지 안 보임. 기존 /file?token= iframe 패턴과 동일하게 access token
쿼리 파라미터로 전달.
backend: get_current_user 의존성 제거하고 token 쿼리 파라미터 직접 검증 (기존 /file
엔드포인트와 동일 흐름).
frontend: MarkdownDoc 의 swap selector 가 img.src 에 ?token={getAccessToken()} 부여.
로그아웃 상태면 placeholder 유지.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+14
-2
@@ -675,14 +675,26 @@ async def get_document_file(
|
||||
async def get_document_image_raw(
|
||||
doc_id: int,
|
||||
image_key: str,
|
||||
user: Annotated[User, Depends(get_current_user)],
|
||||
session: Annotated[AsyncSession, Depends(get_session)],
|
||||
token: str | None = Query(None, description="Bearer token (img 태그용)"),
|
||||
):
|
||||
"""marker 추출 이미지 raw bytes (Phase 1B.5).
|
||||
|
||||
md_content 안의 `` ref 를 frontend selector 가 이 라우트로 변환.
|
||||
인증된 사용자만 응답 (단일 사용자 환경, ownership 컬럼 없음 — get_current_user 게이트 충분).
|
||||
인증된 사용자만 응답 (단일 사용자 환경, ownership 컬럼 없음).
|
||||
|
||||
인증: `<img src=>` 는 Authorization header 를 못 보내므로 `?token=` 쿼리 파라미터
|
||||
로 access token 을 전달 — 기존 `/{doc_id}/file?token=` 엔드포인트 (iframe 용) 와
|
||||
동일 패턴.
|
||||
"""
|
||||
from core.auth import decode_token
|
||||
|
||||
if not token:
|
||||
raise HTTPException(status_code=401, detail="토큰이 필요합니다")
|
||||
payload = decode_token(token)
|
||||
if not payload or payload.get("type") != "access":
|
||||
raise HTTPException(status_code=401, detail="유효하지 않은 토큰")
|
||||
|
||||
# 문서 존재 확인 (image_key 만 있고 doc 가 사라진 케이스 차단)
|
||||
doc = await session.get(Document, doc_id)
|
||||
if doc is None:
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* - md_status badge (processing/success/skipped/failed) — MarkdownStatusBadge 위임
|
||||
*/
|
||||
import { renderDocMarkdown } from '$lib/utils/docMarkdown';
|
||||
import { getAccessToken } from '$lib/api';
|
||||
import MarkdownStatusBadge from '$lib/components/MarkdownStatusBadge.svelte';
|
||||
|
||||
type Props = {
|
||||
@@ -115,8 +116,15 @@
|
||||
if (!key) continue;
|
||||
const alt = ph.getAttribute('data-md-image-alt') ?? '';
|
||||
|
||||
// <img> 는 Authorization header 를 못 보내므로 ?token= 쿼리 파라미터로 access
|
||||
// token 전달 (기존 /api/documents/{id}/file?token= iframe 패턴과 동일).
|
||||
const accessToken = getAccessToken();
|
||||
if (!accessToken) {
|
||||
// 로그아웃 상태 — placeholder 유지
|
||||
continue;
|
||||
}
|
||||
const img = document.createElement('img');
|
||||
img.src = `/api/documents/${documentId}/images/${encodeURIComponent(key)}/raw`;
|
||||
img.src = `/api/documents/${documentId}/images/${encodeURIComponent(key)}/raw?token=${encodeURIComponent(accessToken)}`;
|
||||
img.alt = alt;
|
||||
img.loading = 'lazy';
|
||||
img.className = 'md-image';
|
||||
|
||||
Reference in New Issue
Block a user