forked from baron/baron-sso
121 lines
8.6 KiB
Markdown
121 lines
8.6 KiB
Markdown
# 개발 문서: SMS 인증 기능 구현
|
|
|
|
## 1. 완료된 작업: SMS 인증 전체 플로우 구현 (발송 및 검증)
|
|
|
|
### 작업 내역
|
|
|
|
#### Backend (`Go`)
|
|
|
|
- [x] **Naver SENS API 연동 서비스 구현:** (`internal/service/sms_service.go`)
|
|
* **내용:** Naver SENS API를 호출하여 SMS 발송을 요청하는 핵심 모듈을 구현했습니다.
|
|
* **필요 이유:** 실제 SMS 메시지를 외부로 발송하기 위한 통신 기능이 필요했습니다.
|
|
|
|
- [x] **API 엔드포인트 및 핸들러 추가:** (`cmd/server/main.go`, `internal/handler/auth_handler.go`)
|
|
* **내용:** `POST /api/v1/auth/sms` 엔드포인트를 추가하고, 인증 코드 생성 및 SMS 서비스 호출 로직을 구현했습니다.
|
|
* **필요 이유:** 프론트엔드에서 보낸 SMS 발송 요청을 수신하고 처리하기 위한 접점이 필요했습니다.
|
|
|
|
- [x] **데이터 모델 정의:** (`internal/domain/sms_models.go`)
|
|
* **내용:** API 요청/응답 처리를 위한 Go 데이터 구조(struct)를 정의했습니다.
|
|
* **필요 이유:** JSON 데이터를 Go 코드 내에서 타입-세이프(type-safe)하게 다루기 위해 필요했습니다.
|
|
|
|
- [x] **입력 값 처리 및 로깅 강화:** (`internal/handler/auth_handler.go`)
|
|
* **내용:** 전화번호에서 하이픈(`-`)을 제거하고, 발송/검증 실패 시 상세 오류를 기록하도록 구현했습니다.
|
|
* **필요 이유:** 외부 API의 요구사항을 충족시키고, 운영 중 문제 발생 시 신속하게 원인을 진단하기 위해 필요했습니다.
|
|
|
|
- [x] **Redis 서비스 구현 및 연동:** (`internal/service/redis_service.go`, `internal/handler/auth_handler.go`)
|
|
* **내용:** Redis 클라이언트 초기화, 인증 코드 저장(`StoreVerificationCode`), 조회(`GetVerificationCode`), 삭제(`DeleteVerificationCode`) 기능을 구현하고, `AuthHandler`와 `SendSms` 함수에 Redis 저장 로직을 추가했습니다.
|
|
* **필요 이유:** 발급된 인증 코드를 임시로 저장하여 사용자가 나중에 입력한 코드와 비교 검증하기 위한 안정적인 저장소가 필요했습니다.
|
|
|
|
- [x] **인증 코드 검증 API 엔드포인트 구현:** (`cmd/server/main.go`, `internal/handler/auth_handler.go`, `internal/domain/sms_models.go`)
|
|
* **내용:** `POST /api/v1/auth/verify-sms` 엔드포인트를 추가하고, 사용자가 입력한 코드와 Redis에 저장된 코드를 비교 검증하는 `VerifySms` 함수를 구현했습니다. 관련 데이터 모델도 추가했습니다.
|
|
* **필요 이유:** 사용자가 받은 인증 코드를 백엔드에서 확인하고, 인증 성공/실패 여부를 결정하기 위한 API와 로직이 필요했습니다.
|
|
|
|
- [x] **인증 성공 시 JWT 발급 로직:** (`internal/handler/auth_handler.go`)
|
|
* **내용:** 코드 검증이 성공하면, 해당 사용자에 대한 세션 토큰(JWT)을 생성하여 프론트엔드에 반환합니다.
|
|
* **필요 이유:** 사용자가 로그인 상태를 유지하고, 인증이 필요한 다른 API를 호출할 수 있도록 하기 위함입니다.
|
|
|
|
#### Frontend (`Flutter`)
|
|
|
|
- [x] **SMS 인증 요청 서비스 구현:** (`lib/core/services/auth_proxy_service.dart`)
|
|
* **내용:** 백엔드의 SMS 발송 API를 호출하는 `sendSms` 함수를 추가했습니다.
|
|
* **필요 이유:** UI와 백엔드 API 간의 통신을 담당하는 재사용 가능한 서비스 계층을 만들어 코드의 관심사를 분리하기 위해 필요했습니다.
|
|
|
|
- [x] **로그인 화면 UI/UX 개선:** (`lib/features/auth/presentation/login_screen.dart`)
|
|
* **내용:** 이메일/SMS 인증 탭 UI와 전화번호 입력 필드 및 버튼을 구현했습니다.
|
|
* **필요 이유:** 사용자가 SMS 인증 방식을 선택하고 사용할 수 있는 명확한 UI가 필요했습니다.
|
|
|
|
- [x] **SMS 인증 발송 플로우 로직 구현:** (`lib/features/auth/presentation/login_screen.dart`)
|
|
* **내용:** '인증 코드 발송' 버튼 클릭 시 API를 호출하고, 결과에 따라 UI 상태를 동적으로 변경하는 로직을 구현했습니다.
|
|
* **필요 이유:** 사용자의 상호작용에 응답하고, 통신 결과에 따라 UI를 동적으로 변경하는 로직이 필요했습니다.
|
|
|
|
- [x] **인증 코드 검증 서비스 구현:** (`lib/core/services/auth_proxy_service.dart`)
|
|
* **내용:** `AuthProxyService`에 백엔드의 `verify-sms` API를 호출하는 함수를 추가했습니다.
|
|
* **필요 이유:** 인증 코드 검증을 위해 백엔드와 통신하는 서비스 로직이 필요했습니다.
|
|
|
|
- [x] **인증 코드 검증 플로우 로직 구현:** (`lib/features/auth/presentation/login_screen.dart`)
|
|
* **내용:** '코드 확인' 버튼 클릭 시, 입력된 코드와 전화번호를 백엔드로 보내 검증을 요청하는 로직을 구현했습니다.
|
|
* **필요 이유:** 사용자의 코드 제출 액션에 응답하는 로직이 필요했습니다.
|
|
|
|
- [x] **인증 결과 처리:** (`lib/features/auth/presentation/login_screen.dart`)
|
|
* **내용:** 검증 성공 시 JWT를 콘솔에 출력하고 성공 다이얼로그를 표시합니다. (JWT 저장 및 대시보드 이동은 `TODO` 상태)
|
|
* **필요 이유:** 인증 결과에 따라 사용자에게 적절한 피드백(화면 전환 또는 오류 안내)을 제공해야 합니다.
|
|
|
|
### 전체 인증 플로우: 시퀀스 다이어그램
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant 사용자
|
|
participant Flutter as Flutter (Frontend)
|
|
participant Go as Go (Backend)
|
|
participant NaverSMS as Naver SMS API
|
|
|
|
Note over 사용자, NaverSMS: 1. 인증 코드 발송 단계
|
|
사용자->>Flutter: 전화번호 입력 후 '인증 코드 발송' 요청
|
|
Flutter->>Go: POST /api/v1/auth/sms
|
|
Go->>Go: 6자리 인증 코드 생성 & 임시 저장 (Redis)
|
|
Go->>NaverSMS: SMS 발송 요청 (인증 코드 포함)
|
|
NaverSMS-->>사용자: [SMS] 인증번호 메시지 수신
|
|
NaverSMS-->>Go: 발송 요청 결과 응답
|
|
Go-->>Flutter: 처리 결과 응답 (성공)
|
|
Flutter->>사용자: UI 업데이트 (인증번호 입력창 표시)
|
|
|
|
Note over 사용자, Go: 2. 인증 코드 검증 단계
|
|
사용자->>Flutter: 수신한 인증 코드 입력 후 '코드 확인' 요청
|
|
Flutter->>Go: POST /api/v1/auth/verify-sms (전화번호, 입력 코드)
|
|
Go->>Go: 임시 저장된 코드와 비교 및 검증 (Redis)
|
|
|
|
alt 인증 성공
|
|
Go->>Go: JWT(세션 토큰) 생성
|
|
Go-->>Flutter: 인증 성공 응답 (JWT 포함)
|
|
Flutter->>Flutter: JWT 수신 및 처리 (저장 및 대시보드 이동 예정)
|
|
Flutter->>사용자: 성공 메시지 표시
|
|
else 인증 실패
|
|
Go-->>Flutter: 인증 실패 응답
|
|
Flutter->>사용자: 오류 메시지 표시
|
|
end
|
|
|
|
```
|
|
|
|
---
|
|
|
|
## 2. 발생 이슈 및 해결 과정 (통합)
|
|
|
|
1. **발신자 번호 미인증 오류**
|
|
* **이슈:** SENS API에서 `'from' is not an authenticated tel number` 오류 반환.
|
|
* **해결:** 네이버 클라우드 플랫폼 콘솔에서 SMS 발신 번호를 등록하고 인증 절차를 완료한 후, `.env` 파일의 `NAVER_SENDER_PHONE_NUMBER` 값을 인증된 번호로 수정.
|
|
|
|
2. **환경 변수 누락으로 인한 API URL 생성 실패**
|
|
* **이슈:** 백엔드 컨테이너가 `NAVER_CLOUD_SERVICE_ID` 환경 변수를 읽지 못해 `URL not found` 오류 발생.
|
|
* **해결:** `docker-compose.yaml`의 `backend` 서비스에 `env_file: [".env"]` 설정을 추가하여 컨테이너가 `.env` 파일의 모든 변수를 로드하도록 수정.
|
|
|
|
3. **전화번호 형식 불일치 오류**
|
|
* **이슈:** SENS API에서 `phone number format excluding dash(-)` 오류 반환.
|
|
* **해결:** 백엔드 `AuthHandler`에서 SENS API로 전화번호를 전달하기 전, `strings.ReplaceAll` 함수를 사용하여 하이픈(-)을 모두 제거하는 로직 추가.
|
|
|
|
4. **Redis 연결 실패 오류**
|
|
* **이슈:** 백엔드 컨테이너가 Redis에 접속하지 못하고 `Failed to connect to Redis: dial tcp [::1]:6379: connect: connection refused` 오류 발생.
|
|
* **해결:** 프로젝트 루트의 `.env` 파일에 `REDIS_ADDR=redis:6379`를 추가하고, `docker-compose up -d --force-recreate` 명령을 통해 컨테이너를 강제로 재생성하여 변경된 환경 변수를 적용.
|
|
|
|
5. **Go 백엔드 빌드 실패 (JWT 라이브러리 import 누락)**
|
|
* **이슈:** Docker 이미지 빌드 중 `undefined: jwt` 컴파일 오류 발생.
|
|
* **해결:** `backend/internal/handler/auth_handler.go` 파일에 `"github.com/golang-jwt/jwt/v4"` import 구문을 추가하여 해결. |