[ 설명 ]
- 구조 자체는 동일
- 예로 owner_id 컬럼으로 사용자 데이터를 구분하는 로직은 그대로
- 하지만 그 ID를 누가 발급하지는 차이점 존재
Before: Spring Seucrity
[ 1. 회원가입 ]
- Spring이 DB에 INSERT -> users.id = 1 (auto_increment)
=> 세션 또는 자체 JWT 발급 (userId: 1 포함)
[ 2. 주문 생성 ]
- session/JWT에서 userId=1 꺼냄
=> orders.owner_id = 1로 저장
[ 3. 주문 조회 ]
- WHERE owner_id = 1
After: Cognito + Spring Security
[ 1. 회원가입 ]
- Cognito에 등록 -> sub="a1b2c3-..." (UUID)
=> Cognito가 JWT 발급 (sub 포함)
[ 2. 주문 생성 ]
- JWT에서 sub="a1b2c3-..." 꺼냄
=> orders.owner_id = "a1b2c3-..." 로 저장
[ 3. 주문 조회 ]
- WHERE owner_id = "a1b2c3-..."
| 항목 | Before | After |
|---|---|---|
| ID 타입 | Long (1, 2, 3...) |
String (UUID) |
| ID 생성 주체 | DB auto_increment | Cognito |
| ID 획득 방법 | 세션/자체 JWT | Cognito JWT의 sub |
| 컬럼 타입 | BIGINT |
VARCHAR(50) |
| 회원 정보 저장 | Spring DB의 users 테이블 | Cognito (+ 필요시 앱 DB 캐시) |
| 비밀번호 관리 | Spring (BCrypt 등) | Cognito |
| 로그인 엔드포인트 | Spring에서 직접 구현 | Cognito Hosted UI |
| 종류 | 질문 | 예시 | 판단에 필요한 정보 |
|---|---|---|---|
| Role-based (coarse) | "이 role이 이 기능을 쓸 수 있나?" | user는 구매, seller는 판매 | JWT만 보면 됨 |
| Ownership-based (fine) | "이 사용자가 이 리소스에 권한 있나?" | A의 장바구니는 A만 | DB를 봐야 알 수 있음 |
[ 설명 ]
- 인가는 근본적으로 두 층위가 존재
- 여기서 Istio/Envoy는 DB를 알수가 없음, /orders/123 요청이 들어왔을 때 "이 주문의 주인이
누구인지"를 알수가 없음
- 이러한 이유는 서비스 메쉬의 철학을 살펴보면 "애플리케이션 관심사를 Infra로 옮긴다"인데
이 말은, 비즈니스 데이터에 의존하지 않는 cross-cutting 관심사를 Infra로 옮긴다는 의미
=> 그래서 여기서 소유자 검증 -> 비즈니스 데이터 필요는 Infra로 빠질 수 없음
[ 1. Client ]
- Authorization: Beader <JWT>
[ 2. Istio RequestAuthentication ]
- JWT 서명& 만료 검증 (인증)
[ 3. Istio AuthorizationPolicy ]
- 경로/role 기반 인가 (거친 필터)
- 이 JWT는 Authroization 헤더에 그대로 담겨 전달
[ 4. Spring App ]
- oauth2ResourceServer가 JWT 재검증 (심층 방어)
- @PreAuthorized로 role 체크
- jwt.getSubject()로 sub 추출
- service/repository에서 WHERE owner_id = :sub
[ 5. DB ]
- 해당 user의 데이터만 반환/저장
GET /me/orders
Authorization: Bearer eyJhGci...