@@ -66,58 +66,63 @@ export class AppleStrategy extends PassportStrategy(Strategy, 'apple') {
6666 done : any ,
6767 ) : Promise < any > {
6868 this . logger . log ( 'Apple 로그인 검증 시작' ) ;
69- this . logger . log ( `요청 본문: ${ JSON . stringify ( request . body ) } ` ) ;
69+ this . logger . log ( `요청 본문: ${ JSON . stringify ( request . body , null , 2 ) } ` ) ;
70+ this . logger . log ( `요청 쿼리: ${ JSON . stringify ( request . query , null , 2 ) } ` ) ;
7071 this . logger . log ( `accessToken: ${ accessToken ? 'present' : 'not present' } ` ) ;
72+ this . logger . log (
73+ `refreshToken: ${ refreshToken ? 'present' : 'not present' } ` ,
74+ ) ;
7175 this . logger . log ( `idToken 유형: ${ typeof idToken } ` ) ;
76+ this . logger . log ( `profile 유형: ${ typeof profile } ` ) ;
77+ this . logger . log ( `profile 내용: ${ JSON . stringify ( profile , null , 2 ) } ` ) ;
7278
7379 try {
7480 let email = '' ;
7581 let providerId = '' ;
7682 let fullName = '' ;
7783
78- // 1. 첫 번째 로그인 시 req.body.user에서 사용자 정보 추출
79- if ( request . body && request . body . user ) {
80- this . logger . log ( '첫 번째 로그인: req.body.user에서 사용자 정보 추출' ) ;
81- const userData = JSON . parse ( request . body . user ) ;
82- this . logger . log ( `사용자 데이터: ${ JSON . stringify ( userData ) } ` ) ;
84+ // 1. profile에서 기본 정보 추출 (passport-apple이 이미 처리한 정보)
85+ if ( profile ) {
86+ this . logger . log ( `profile 정보: ${ JSON . stringify ( profile , null , 2 ) } ` ) ;
87+
88+ // providerId는 profile.id에서 가져옴
89+ if ( profile . id ) {
90+ providerId = profile . id ;
91+ this . logger . log ( `profile에서 providerId 추출: ${ providerId } ` ) ;
92+ }
8393
84- if ( userData . email ) {
85- email = userData . email ;
86- this . logger . log ( `req.body.user에서 이메일 추출: ${ email } ` ) ;
94+ // 이메일 추출
95+ if ( profile . email ) {
96+ email = profile . email ;
97+ this . logger . log ( `profile에서 이메일 추출: ${ email } ` ) ;
8798 }
8899
89- if ( userData . name ) {
90- const firstName = userData . name . firstName || '' ;
91- const lastName = userData . name . lastName || '' ;
100+ // 이름 추출
101+ if ( profile . name ) {
102+ const firstName = profile . name . firstName || '' ;
103+ const lastName = profile . name . lastName || '' ;
92104 fullName = `${ firstName } ${ lastName } ` . trim ( ) ;
93- this . logger . log ( `req.body.user에서 이름 추출: ${ fullName } ` ) ;
105+ this . logger . log ( `profile에서 이름 추출: ${ fullName } ` ) ;
94106 }
95107 }
96108
97- // 2. idToken에서 정보 추출 (JWT 디코딩)
98- if ( idToken ) {
109+ // 2. idToken에서 추가 정보 추출 (JWT 디코딩)
110+ if ( idToken && typeof idToken === 'string' ) {
99111 try {
100- let decodedToken ;
101-
102- // idToken이 문자열인 경우 JWT 디코딩
103- if ( typeof idToken === 'string' ) {
104- this . logger . log ( 'idToken을 JWT로 디코딩 중...' ) ;
105- decodedToken = jwt . decode ( idToken ) as any ;
106- } else if ( typeof idToken === 'object' ) {
107- this . logger . log ( 'idToken이 이미 객체 형태로 제공됨' ) ;
108- decodedToken = idToken ;
109- }
112+ this . logger . log ( 'idToken을 JWT로 디코딩 중...' ) ;
113+ const decodedToken = jwt . decode ( idToken , { json : true } ) as any ;
114+ this . logger . log (
115+ `JWT 디코딩 결과: ${ JSON . stringify ( decodedToken , null , 2 ) } ` ,
116+ ) ;
110117
111118 if ( decodedToken ) {
112- this . logger . log ( `디코딩된 토큰: ${ JSON . stringify ( decodedToken ) } ` ) ;
113-
114- // providerId는 sub 필드에서 가져옴 (Apple 사용자 고유 ID)
115- if ( decodedToken . sub ) {
119+ // providerId가 없으면 sub에서 가져옴
120+ if ( ! providerId && decodedToken . sub ) {
116121 providerId = decodedToken . sub ;
117122 this . logger . log ( `idToken에서 providerId 추출: ${ providerId } ` ) ;
118123 }
119124
120- // 이메일이 없으면 idToken에서 시도
125+ // 이메일이 없으면 idToken에서 가져옴
121126 if ( ! email && decodedToken . email ) {
122127 email = decodedToken . email ;
123128 this . logger . log ( `idToken에서 이메일 추출: ${ email } ` ) ;
@@ -136,19 +141,73 @@ export class AppleStrategy extends PassportStrategy(Strategy, 'apple') {
136141 }
137142 }
138143 } catch ( tokenError ) {
139- this . logger . error ( `idToken 처리 오류: ${ tokenError . message } ` ) ;
144+ this . logger . error ( `idToken JWT 디코딩 오류: ${ tokenError . message } ` ) ;
145+ }
146+ }
147+
148+ // 3. 첫 번째 로그인 시 req.body.user에서 사용자 정보 추출
149+ if ( request . body && request . body . user ) {
150+ this . logger . log ( '첫 번째 로그인: req.body.user에서 사용자 정보 추출' ) ;
151+ try {
152+ let userData ;
153+ if ( typeof request . body . user === 'string' ) {
154+ userData = JSON . parse ( request . body . user ) ;
155+ } else {
156+ userData = request . body . user ;
157+ }
158+
159+ this . logger . log (
160+ `사용자 데이터: ${ JSON . stringify ( userData , null , 2 ) } ` ,
161+ ) ;
162+
163+ if ( userData . email && ! email ) {
164+ email = userData . email ;
165+ this . logger . log ( `req.body.user에서 이메일 추출: ${ email } ` ) ;
166+ }
167+
168+ if ( userData . name && ! fullName ) {
169+ const firstName = userData . name . firstName || '' ;
170+ const lastName = userData . name . lastName || '' ;
171+ fullName = `${ firstName } ${ lastName } ` . trim ( ) ;
172+ this . logger . log ( `req.body.user에서 이름 추출: ${ fullName } ` ) ;
173+ }
174+ } catch ( parseError ) {
175+ this . logger . error ( `req.body.user 파싱 오류: ${ parseError . message } ` ) ;
140176 }
141177 }
142178
143- // 3 . 여전히 이메일이 없으면 에러
179+ // 4 . 여전히 이메일이 없으면 임시 이메일 생성
144180 if ( ! email ) {
145- this . logger . error ( '이메일 정보를 찾을 수 없습니다.' ) ;
146- throw new Error (
147- 'Apple 로그인에서 이메일 정보를 가져올 수 없습니다. 이메일 공유를 허용해주세요.' ,
181+ this . logger . warn (
182+ '이메일 정보를 찾을 수 없음 - providerId 기반 임시 이메일 생성' ,
148183 ) ;
184+
185+ if ( providerId ) {
186+ // providerId를 기반으로 임시 이메일 생성
187+ email = `apple_${ providerId } @privaterelay.appleid.com` ;
188+ this . logger . log ( `providerId 기반 임시 이메일 생성: ${ email } ` ) ;
189+ } else {
190+ // Apple에서 제공하는 code나 다른 정보로 임시 이메일 생성
191+ const code = request . body ?. code ;
192+ if ( code ) {
193+ // code를 기반으로 임시 이메일 생성
194+ const codeHash = crypto
195+ . createHash ( 'sha256' )
196+ . update ( code )
197+ . digest ( 'hex' )
198+ . substring ( 0 , 12 ) ;
199+ email = `apple_${ codeHash } @privaterelay.appleid.com` ;
200+ this . logger . log ( `code 기반 임시 이메일 생성: ${ email } ` ) ;
201+ } else {
202+ // 완전히 랜덤한 임시 이메일 생성
203+ const randomId = crypto . randomBytes ( 8 ) . toString ( 'hex' ) ;
204+ email = `apple_${ randomId } @privaterelay.appleid.com` ;
205+ this . logger . log ( `랜덤 임시 이메일 생성: ${ email } ` ) ;
206+ }
207+ }
149208 }
150209
151- // 4 . providerId가 없으면 이메일 기반으로 생성
210+ // 5 . providerId가 없으면 이메일 기반으로 생성
152211 if ( ! providerId ) {
153212 this . logger . warn (
154213 'providerId를 찾을 수 없어 이메일 기반 ID를 생성합니다' ,
@@ -165,7 +224,7 @@ export class AppleStrategy extends PassportStrategy(Strategy, 'apple') {
165224 this . logger . log ( `이메일 기반 providerId 생성: ${ providerId } ` ) ;
166225 }
167226
168- // 5 . 이름이 없으면 이메일에서 추출
227+ // 6 . 이름이 없으면 이메일에서 추출
169228 if ( ! fullName ) {
170229 fullName = email . split ( '@' ) [ 0 ] ;
171230 this . logger . log ( `이메일에서 사용자명 생성: ${ fullName } ` ) ;
@@ -183,7 +242,7 @@ export class AppleStrategy extends PassportStrategy(Strategy, 'apple') {
183242 accessToken : accessToken || 'apple_token' ,
184243 } ;
185244
186- this . logger . log ( `생성된 사용자 객체: ${ JSON . stringify ( user ) } ` ) ;
245+ this . logger . log ( `생성된 사용자 객체: ${ JSON . stringify ( user , null , 2 ) } ` ) ;
187246
188247 // 사용자 인증 처리
189248 const result = await this . authService . validateOAuthUser ( user , 'apple' ) ;
0 commit comments