feat: P6 모바일 PWA 보안 강화 — /api/mobile/me/* 서버측 본인 필터
스캐폴드의 클라이언트 agentId 쿼리 필터(변조 가능)를
서버측 강제 필터로 교체. 토큰 → user → agentId 자동 추출.
백엔드 (ga-api):
- MobileMeService — 클라이언트 param 의 agentId/userId 는 무시·덮어쓰기.
agentId 미연결 시 BizException(FORBIDDEN). PageHelper 로 정확한 total 산출.
- MobileMeController — GET /api/mobile/me/{summary,statements,
withdraw-requests,notifications} + POST /notifications/{id}/read.
별도 메뉴 권한 없이 인증만 통과 (PWA 사용자 전체 대상).
ga-mobile-pwa:
- api/statement.ts, api/withdraw.ts → /api/mobile/me/* 호출, agentId 제거
- api/notification.ts 신규 — list/markRead/summary
- Home.tsx — summary() 단일 호출로 3카운트 + 안 읽음 Badge
- NoticeList.tsx — Tabs(내 알림 / 공지). 알림 클릭 markRead + summary 무효화
- Statement/WithdrawList — E403(설계사 미연결) 시 ErrorBlock 안내
라이브 검증:
- ga-api 컴파일 BUILD SUCCESSFUL · 재기동 OK
- PWA tsc PASS · vite build PASS (precache 538KB, gzip 176KB)
- admin(agentId=null): /summary → 200 OK 0/0/0,
/statements → E403 차단 정상, /notifications → 200 OK total=0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+27
-2
@@ -339,14 +339,39 @@ npm run preview # 3001 에서 production 번들 서빙
|
||||
- API 응답 확인: `/api/statements` total=112, `/api/withdraw-requests` total=3, `/api/notices/active` 0건(정상), `/api/auth/me` 정상
|
||||
|
||||
### 잔여 (스캐폴드 이후)
|
||||
- 백엔드 `/api/mobile/me/*` 전용 endpoint (서버측 본인 필터 강제)
|
||||
- ~~백엔드 `/api/mobile/me/*` 전용 endpoint~~ → §3-14 에서 완료
|
||||
- ~~본인 알림(`user_notification`) 표시~~ → §3-14 에서 완료
|
||||
- 출금 신청 작성 폼 (현재 이력 조회만)
|
||||
- 정산 명세서 상세 + PDF 다운로드
|
||||
- 본인 알림(`user_notification`) 표시 + 토큰 만료 자동 refresh
|
||||
- 토큰 만료 자동 refresh
|
||||
- 푸시 알림 (FCM 등) — 외부 채널 결정 후
|
||||
- 실 아이콘 PNG (192/512/512 maskable)
|
||||
- 번들 코드 스플리팅 (manualChunks)
|
||||
|
||||
## 3-14. P6 — 모바일 PWA 보안 강화: `/api/mobile/me/*` 전용 endpoint (2026-05-24)
|
||||
|
||||
PWA 스캐폴드에서 클라이언트가 `agentId` 를 쿼리 파라미터로 보내 본인 데이터를 필터하던 변조 가능 구조를 **서버측 강제 필터**로 교체. 토큰 → user → agentId 자동 추출.
|
||||
|
||||
### 백엔드 신규
|
||||
| 위치 | 내용 |
|
||||
|---|---|
|
||||
| `ga-api/service/mobile/MobileMeService` | 토큰에서 userId 추출, `userMapper.selectById` 로 agentId 결정. 클라이언트 param 의 agentId/userId 는 **무시하고 덮어쓰기**. agentId 미연결 시 `BizException(FORBIDDEN)` |
|
||||
| `ga-api/controller/mobile/MobileMeController` | `GET /api/mobile/me/{summary,statements,withdraw-requests,notifications}` + `POST /api/mobile/me/notifications/{id}/read`. 별도 메뉴 권한 없이 인증만 통과 |
|
||||
|
||||
### PWA 측 전환
|
||||
- `src/api/statement.ts` / `withdraw.ts` → `/api/mobile/me/*` 호출, `agentId` 인터페이스에서 제거
|
||||
- `src/api/notification.ts` 신규 — list/markRead/summary
|
||||
- `Home.tsx` — `notificationApi.summary()` 한 번으로 3 카운트 동시 표시, 안 읽음 뱃지
|
||||
- `NoticeList.tsx` — `Tabs` 로 `내 알림` / `공지사항` 두 탭. 알림 클릭 시 markRead + summary 무효화
|
||||
- `StatementList.tsx` / `WithdrawList.tsx` — agentId 의존 제거, E403(설계사 미연결) 시 ErrorBlock 안내
|
||||
|
||||
### 라이브 검증 (2026-05-24)
|
||||
- ga-api 컴파일 BUILD SUCCESSFUL · 재기동 OK
|
||||
- PWA `tsc --noEmit` PASS · `npm run build` PASS (precache 8 entries 538 KiB, gzip 176KB)
|
||||
- `GET /api/mobile/me/summary` (admin, agentId=null) → 200 OK, 세 카운트 모두 0
|
||||
- `GET /api/mobile/me/statements` (admin) → **E403** 차단 (보안 강제 동작 확인)
|
||||
- `GET /api/mobile/me/notifications` (admin) → 200 OK total=0
|
||||
|
||||
## 4. 잔여 작업 (P6 실연동)
|
||||
|
||||
P5 전체 + P6 PoC(어댑터 모듈 + Mock + SDK 분기 + 재시도 + 추적 컬럼 + 호출 감사 이력 + **모바일 PWA 스캐폴드**) 완료.
|
||||
|
||||
Reference in New Issue
Block a user