fix(products): 모달 401 세션만료 처리 + callback open redirect 방어 + 초기 포커스
- BankTransferModal: POST /api/orders 401 응답 시 setAuthState('guest')로 전환 (에러 텍스트 대신 로그인 유도 UI 복귀)
- BankTransferModal: 모달 열릴 때 closeBtnRef.current?.focus() 호출 (접근성 초기 포커스)
- auth/callback: next 파라미터를 safeNext 패턴으로 검증 — startsWith('/') && !startsWith('//') && !startsWith('/\') 미충족 시 /mypage 폴백
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,11 @@ import { createClient } from '@/lib/supabase/server';
|
|||||||
export async function GET(request: Request) {
|
export async function GET(request: Request) {
|
||||||
const { searchParams, origin } = new URL(request.url);
|
const { searchParams, origin } = new URL(request.url);
|
||||||
const code = searchParams.get('code');
|
const code = searchParams.get('code');
|
||||||
const next = searchParams.get('next') ?? '/mypage';
|
const rawNext = searchParams.get('next') ?? '/mypage';
|
||||||
|
const next =
|
||||||
|
rawNext.startsWith('/') && !rawNext.startsWith('//') && !rawNext.startsWith('/\\')
|
||||||
|
? rawNext
|
||||||
|
: '/mypage';
|
||||||
|
|
||||||
// 리다이렉트 기준 URL 결정
|
// 리다이렉트 기준 URL 결정
|
||||||
// - dev: 항상 현재 request의 origin (localhost) → NEXT_PUBLIC_SITE_URL 무시
|
// - dev: 항상 현재 request의 origin (localhost) → NEXT_PUBLIC_SITE_URL 무시
|
||||||
|
|||||||
@@ -82,6 +82,11 @@ export default function BankTransferModal({ product, isOpen, onClose }: Props) {
|
|||||||
};
|
};
|
||||||
}, [isOpen, onClose]);
|
}, [isOpen, onClose]);
|
||||||
|
|
||||||
|
// 초기 포커스: 모달 열릴 때 닫기 버튼으로 포커스 이동
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen) closeBtnRef.current?.focus();
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
const handleSubmit = useCallback(
|
const handleSubmit = useCallback(
|
||||||
async (e: React.FormEvent) => {
|
async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -97,6 +102,11 @@ export default function BankTransferModal({ product, isOpen, onClose }: Props) {
|
|||||||
});
|
});
|
||||||
const data = await res.json().catch(() => ({}));
|
const data = await res.json().catch(() => ({}));
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
|
if (res.status === 401) {
|
||||||
|
setSubmitting(false);
|
||||||
|
setAuthState('guest');
|
||||||
|
return;
|
||||||
|
}
|
||||||
setError(data?.error || '주문 처리 중 오류가 발생했습니다. 잠시 후 다시 시도해주세요.');
|
setError(data?.error || '주문 처리 중 오류가 발생했습니다. 잠시 후 다시 시도해주세요.');
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user