16. 기획 - JWT ( spring/supabase )

2025. 4. 22. 23:52현 프로젝트 시작단계

728x90

나는 현재 

프론트엔드 flutter

백엔드 spring 을 이용해서 만들고있고

 

보조 서버로 supabase를 이용하고있다. 

그래서 이러한 구조로 만들어 볼까 생각했다. 

 

 


✅ 결론 먼저:


Supabase는 "즉시 사용 가능한 인증 & 간단한 실시간 데이터 처리"에 최적화


Spring은 "복잡한 로직, 정교한 보안, 대규모 커뮤니티 기능"에 최적화
 이 둘을 역할에 따라 분리하면 각자의 강점을 최대한 살릴려고 하고있다.

 

서버 두개 병행 이유

Supabase와 Spring Boot를 병행 사용한 이유는 각 기술의 강점을 극대화하기 위함입니다. Supabase는 인증(Auth) 및 간단한 데이터 처리에 최적화되어 있어 빠른 MVP 개발과 클라이언트 측 통합에 효과적이며, 실시간 동기화 기능도 제공됩니다. 반면, 커뮤니티 기능과 같이 복잡한 비즈니스 로직이나 권한 처리, 데이터 관계가 중요한 부분은 Spring Boot를 통해 구현하여 유연성과 보안성을 확보했습니다. 이를 통해 인증과 실시간 처리에는 Supabase의 장점을 활용하고, 핵심 서버 로직은 Spring에서 집중 관리함으로써, 개발 효율성과 확장성을 동시에 달성할 수 있었습니다.

 


전체 이렇게 한이유 

 

1. 기능 분리로 책임이 명확해짐 (Separation of Concerns)

 

인증을 Supabase에 맡기면 → Spring은 인증로직 없이 비즈니스만 집중 가능
DB 구조도 단순/복잡 분리 → 설계 명확

✅ 왜 좋냐면?
유지보수 시 어느 로직이 어디 있는지 혼란 없음
협업 시 역할 나누기 쉬움 (ex. 인증 담당, 커뮤니티 담당)

 

 

⚡ 2. 개발 속도 향상 (빠른 MVP 구현)
Supabase는 로그인/회원가입, 테이블 CRUD를 SDK로 바로 처리 가능
빠르게 UI/UX 구성 가능 (Flutter에서 직접 Supabase 사용)
Spring은 로직이 복잡한 기능에 집중 가능 (게시판, 신고, 추천 알고리즘 등)
✅ 왜 좋냐면?
MVP 단계에서 리소스를 덜 쓰고 빠르게 기능을 확인 가능
개발 초기에는 Supabase만으로도 앱 구동 가능 → 점차 Spring 기능 붙여가기 쉬움

 

🔒 3. 보안과 유연성의 균형
Supabase Auth가 JWT 발급 → Spring에서 검증만 하면 인증 로직 노출 X
권한이 필요한 API는 Spring에서 role 기반 처리 가능
복잡한 권한 처리 (ex. 신고 누적 시 글 제한)는 Spring에서만 처리
✅ 왜 좋냐면?
인증은 외부 보안 서비스에 맡기되, 중요한 권한처리/비즈니스는 직접 통제 가능
클라이언트가 모든 걸 Supabase만 통해 처리하면 보안 구멍이 생기기 쉬움

 

📈 4. 성능 최적화 가능

✅ 왜 좋냐면?
Supabase는 실시간이 강점인데, 대량 쿼리는 약함
반대로 Spring은 JPA/QueryDSL 등으로 성능 최적화가 자유로움 → 각자 장점

을 살림

 

🛠️ 5. 운영과 확장성 측면에서 유리
Supabase는 서버리스 = 운영 편함, 실시간 sync 제공
Spring은 서버 제어 가능 = API 로깅, 보안 규칙, admin 기능 확장 가능
추후 인증 자체를 Spring으로 옮겨도 단계적 전환이 가능함
✅ 왜 좋냐면?
초반에는 Supabase + Spring 조합 → 빠름
추후 확장 시엔 Spring이 중심이 되는 구조로 이행도 쉬움

 

 

 

전체 흐름

 

🔐 Supabase JWT 인증 + Spring 연동 방식
Supabase에서 발급한 JWT 토큰을 Spring에서 받아 검증
Spring에서는 Supabase 공개 키(JWK)를 통해 JWT 서명 확인 및 사용자 정보 추출
이를 기반으로 Spring Security 인증 컨텍스트 설정하여 API 접근 통제
프론트에서는 Supabase 로그인만으로 모든 인증 흐름이 동작함

 

 

전체 동작은

📚 프로젝트 전체 흐름 요약
사용자는 Supabase Auth로 로그인
JWT 토큰이 발급되어 Flutter 앱에 저장됨
Flutter는 이 토큰을 Spring API 호출 시 헤더에 포함
Spring은 JWT를 검증하고 사용자 인증 처리
관심매장, 기본 프로필은 Supabase DB에서 직접 읽음
피드, 댓글, 좋아요 등은 Spring API 통해 처리

 

 

내가 하고 싶은 방식

[Flutter] 이메일+비번 입력
   ↓
[Supabase] 로그인 성공 → JWT 발급
   ↓
[Flutter] JWT 헤더에 넣고 Spring 서버로 요청
   ↓
[Spring 서버] JWT 검증 → uuid 꺼내서 인증
   ↓
[Spring 서버] 인증 성공 → 커뮤니티 글쓰기 OK

 

 

사진으로 보면 쉽다 .

 

이메일 치고 로그인 하면 jwt 정보가 생성됨 

그리고 public을 누르면 서버에서 jwt에서 uuid를 뽑아냄 

그래서 uuid가 나오게됨  ( 밑에 자세하게 설명) 

 

1. 코드 개요 및 흐름
목적: Flutter 클라이언트(이전 질문의 코드)에서 Supabase로 로그인 후 받은 JWT를 Spring 서버로 전송해 인증 및 API 호출을 처리.
주요 기능:
Supabase의 JWK(JSON Web Key)에서 공개키를 가져와 JWT 서명을 검증.
JWT를 기반으로 인증된 사용자에게 /api/private/hello 엔드포인트를 제공.
인증 없이 접근 가능한 /api/public/hello 엔드포인트를 제공.
CORS 및 Spring Security 설정으로 클라이언트(Flutter 웹) 요청을 안전하게 처리.

 

2. 각 클래스 및 역할
JwkUtil
역할: Supabase의 JWK URL에서 공개키를 가져옴.
주요 로직:
getPublicKeyFromJwk: JWK URL에서 JSON 데이터를 읽고, 첫 번째 RSA 키를 파싱해 RSAPublicKey를 반환.
Supabase는 JWK 형식으로 공개키를 제공하므로, 이를 통해 JWT 서명을 검증할 수 있음.
사용처: JwtUtil에서 공개키를 사용해 JWT 검증.

JwtUtil
역할: Supabase에서 발급된 JWT의 유효성을 검증.
주요 로직:
validateJwtToken: JWT를 파싱해 JWSObject로 변환 후, 제공된 공개키로 서명을 검증.
Nimbus JOSE 라이브러리를 사용해 RSA 기반 서명 검증.
특징: Supabase의 JWT는 RSA 알고리즘으로 서명되므로, JWK에서 가져온 공개키로 검증.
JwtAuthenticationFilter
역할: HTTP 요청에서 JWT를 추출하고 검증해 인증 정보를 Spring Security 컨텍스트에 설정.
주요 로직:
extractJwtToken: 요청 헤더에서 Authorization: Bearer <token>을 추출.
validateJwtToken: JWT를 검증 (여기서는 HMAC 키 기반 검증, 실제로는 JwtUtil의 RSA 검증과 통합 필요).
getClaims: 검증된 JWT에서 클레임(예: sub에 사용자 ID 포함)을 추출.
인증 성공 시 UsernamePasswordAuthenticationToken을 생성해 Security 컨텍스트에 설정.
문제점: 코드에서 HMAC 키(jwtSecret)를 사용하지만, Supabase는 RSA 서명을 사용하므로 JwtUtil의 공개키 검증 로직과 통합 필요.

PrivateController
역할: 인증된 사용자만 접근 가능한 보호된 API 제공.
주요 로직:
/private/hello 엔드포인트는 "인증된 사용자만 볼 수 있는 응답"을 반환.
특징: Spring Security에서 /api/private/** 경로는 authenticated()로 설정, JWT 인증 필요.
SecurityConfig
역할: Spring Security 설정 및 CORS 활성화.
주요 로직:

/api/private/**: 인증 필요.
기타 요청: 모두 허용.
필터 추가: JwtAuthenticationFilter를 UsernamePasswordAuthenticationFilter 앞에 추가해 JWT 검증 처리.
CORS 설정:
Flutter 웹 클라이언트(http://localhost:55038) 요청 허용.
GET, POST 등 메서드와 인증 정보(AllowCredentials) 허용.
CSRF 비활성화: REST API 특성상 CSRF 보호 불필요.

 

3. 전체 흐름
클라이언트 요청:
Flutter 앱에서 Supabase로 로그인 후 JWT를 받아 Spring 서버로 요청 전송.
보호된 API(/api/private/hello) 호출.
JWT 검증:
JwtAuthenticationFilter가 요청 헤더에서 JWT를 추출.
JwkUtil로 Supabase JWK에서 공개키를 가져오고, JwtUtil로 JWT 서명 검증.
유효한 JWT면 사용자 ID(sub)를 추출해 Spring Security 컨텍스트에 인증 정보 설정.
API 처리:
/api/private/hello: 인증된 사용자만 응답.
CORS 설정으로 Flutter 웹 요청 허용.
응답:
성공 시 API 응답(예: "인증된 사용자만 볼 수 있는 응답") 반환.
실패 시 401(Unauthorized) 또는 에러 메시지.

728x90