React Native에서 Parse와 Apple 로그인 구현하기
React Native용 Apple로 로그인하기
소개
지난 튜토리얼에서는 Parse.User 클래스를 사용하여 앱에 사용자 로그인/로그아웃 기능을 추가했습니다. 이제 Apple Sign-in을 사용하여 Apple에서 사용자 데이터를 검색하고 로그인, 가입 또는 기존 사용자와 연결하는 방법을 배울 것입니다. 또한 이를 달성하기 위해 react-native-apple-authentication 라이브러리를 설치하고 구성할 것입니다.
Parse.User.linkWith 메서드는 각기 다른 제공자가 요청하는 올바른 매개변수만 전달하면 모든 서드파티 인증 방법을 사용하여 사용자를 가입시키고 로그인하는 역할을 합니다. 사용자 데이터를 새 또는 기존 Parse.User에 연결한 후, Parse는 장치에 유효한 사용자 세션을 저장합니다. 이후 currentAsync와 같은 메서드를 호출하면 일반 로그인과 마찬가지로 사용자 데이터를 성공적으로 검색할 수 있습니다.
언제든지 이 튜토리얼로 구축된 전체 Android 프로젝트에 접근할 수 있습니다. GitHub 리포지토리에서 확인하세요.
전제 조건
이 튜토리얼을 완료하려면 다음이 필요합니다:
목표
React Native 앱에서 Parse를 사용하여 Apple Sign-in을 통한 사용자 로그인 기능을 구축합니다.
1 - 의존성 설치
React Native에서 Apple Sign-in을 활성화하는 가장 인기 있는 방법은 react-native-apple-authentication 라이브러리를 사용하는 것입니다. 이 라이브러리의 구성은 개발 환경, 대상 플랫폼 및 선호도에 따라 다르므로, 공식 문서를 따라 설정하세요.
Android용으로 개발하는 경우, Apple JWT 토큰을 디코딩하기 위해 jwt-decode 라이브러리를 설치해야 합니다.
참고: Xcode 환경의 초기 설정, 앱 ID, 키 및 Apple Developer 포털에서 서비스 ID를 만드는 지침을 철저히 따르세요.
2 - Parse와 함께 Apple Sign-in 사용하기
이제 Apple Sign-in 인증 모달을 호출하는 UserLogIn 컴포넌트 내에 새로운 메서드를 생성해 보겠습니다. react-native-apple-authentication 라이브러리는 사용자 플랫폼에 따라 이 호출을 처리하기 위해 두 개의 별도 모듈을 가지고 있으므로, appleAuth.performRequest를 iOS에서 사용하고, appleAuthAndroid.signIn을 Android에서 사용해야 합니다. 사용자가 Apple로 로그인하면, 이 호출은 Apple로부터 사용자 데이터를 검색하고, id, token, 그리고 나중에 사용할 Apple 이메일을 저장해야 합니다.
1 const doUserLogInApple = async function (): Promise<boolean> {
2 try {
3 let response = {};
4 let appleId = '';
5 let appleToken = '';
6 let appleEmail = '';
7 if (Platform.OS === 'ios') {
8 // Performs login request requesting user email
9 response = await appleAuth.performRequest({
10 requestedOperation: appleAuth.Operation.LOGIN,
11 requestedScopes: [appleAuth.Scope.EMAIL],
12 });
13 // On iOS, user ID and email are easily retrieved from request
14 appleId = response.user;
15 appleToken = response.identityToken;
16 appleEmail = response.email;
17 } else if (Platform.OS === 'android') {
18 // Configure the request
19 appleAuthAndroid.configure({
20 // The Service ID you registered with Apple
21 clientId: 'YOUR_SERVICE_ID',
22 // Return URL added to your Apple dev console
23 redirectUri: 'YOUR_REDIRECT_URL',
24 responseType: appleAuthAndroid.ResponseType.ALL,
25 scope: appleAuthAndroid.Scope.ALL,
26 });
27 response = await appleAuthAndroid.signIn();
28 // Decode user ID and email from token returned from Apple,
29 // this is a common workaround for Apple sign-in via web API
30 const decodedIdToken = jwt_decode(response.id_token);
31 appleId = decodedIdToken.sub;
32 appleToken = response.id_token;
33 appleEmail = decodedIdToken.email;
34 }
35 // Format authData to provide correctly for Apple linkWith on Parse
36 const authData = {
37 id: appleId,
38 token: appleToken,
39 };
40 } catch (error) {
41 // Error can be caused by wrong parameters or lack of Internet connection
42 Alert.alert('Error!', error);
43 return false;
44 }
45 };Android의 경우 Apple에서 반환된 토큰을 디코딩해야 한다는 점에 유의하세요. 왜냐하면 라이브러리 react-native-apple-authentication은 인증을 위해 Apple Sign-in 웹 API를 사용하기 때문입니다. 이 방법을 사용할 때 데이터 접근에 대한 제한이 있으므로, 사용자 ID와 이메일을 가져오는 일반적인 우회 방법은 이 디코딩 과정을 통해 이루어집니다. 이는 공식 Parse 가이드에서 여기에 명시되어 있습니다.
그 후, 새로운 Parse.User.linkWith를 사용하여 새로운 사용자 등록 및 로그인을 할 수 있습니다. 사용자가 이미 이 Apple 인증을 사용하여 가입한 경우, linkWith는 기존 계정을 사용하여 그를 로그인 시킵니다.
1 const doUserLogInApple = async function (): Promise<boolean> {
2 try {
3 let response = {};
4 let appleId = '';
5 let appleToken = '';
6 let appleEmail = '';
7 if (Platform.OS === 'ios') {
8 // Performs login request requesting user email
9 response = await appleAuth.performRequest({
10 requestedOperation: appleAuth.Operation.LOGIN,
11 requestedScopes: [appleAuth.Scope.EMAIL],
12 });
13 // On iOS, user ID and email are easily retrieved from request
14 appleId = response.user;
15 appleToken = response.identityToken;
16 appleEmail = response.email;
17 } else if (Platform.OS === 'android') {
18 // Configure the request
19 appleAuthAndroid.configure({
20 // The Service ID you registered with Apple
21 clientId: 'YOUR_SERVICE_IO',
22 // Return URL added to your Apple dev console
23 redirectUri: 'YOUR_SERVICE_URL',
24 responseType: appleAuthAndroid.ResponseType.ALL,
25 scope: appleAuthAndroid.Scope.ALL,
26 });
27 response = await appleAuthAndroid.signIn();
28 // Decode user ID and email from token returned from Apple,
29 // this is a common workaround for Apple sign-in via web API
30 const decodedIdToken = jwt_decode(response.id_token);
31 appleId = decodedIdToken.sub;
32 appleToken = response.id_token;
33 appleEmail = decodedIdToken.email;
34 }
35 // Format authData to provide correctly for Apple linkWith on Parse
36 const authData = {
37 id: appleId,
38 token: appleToken,
39 };
40 // Log in or sign up on Parse using this Apple credentials
41 let userToLogin = new Parse.User();
42 // Set username and email to match provider email
43 userToLogin.set('username', appleEmail);
44 userToLogin.set('email', appleEmail);
45 return await userToLogin
46 .linkWith('apple', {
47 authData: authData,
48 })
49 .then(async (loggedInUser) => {
50 // logIn returns the corresponding ParseUser object
51 Alert.alert(
52 'Success!',
53 `User ${loggedInUser.get('username')} has successfully signed in!`,
54 );
55 // To verify that this is in fact the current user, currentAsync can be used
56 const currentUser = await Parse.User.currentAsync();
57 console.log(loggedInUser === currentUser);
58 // Navigation.navigate takes the user to the screen named after the one
59 // passed as parameter
60 navigation.navigate('Home');
61 return true;
62 })
63 .catch(async (error) => {
64 // Error can be caused by wrong parameters or lack of Internet connection
65 Alert.alert('Error!', error.message);
66 return false;
67 });
68 } catch (error) {
69 // Error can be caused by wrong parameters or lack of Internet connection
70 Alert.alert('Error!', error);
71 return false;
72 }
73 };이 기능을 UserSignIn 컴포넌트에 추가하고 Apple 버튼의 onPress 매개변수에 할당하세요. 새 기능을 테스트해 보세요. 사용자가 성공적으로 등록하고/또는 로그인한 후에는 홈 화면으로 리디렉션된다는 점에 유의하세요.

3 - 사용자 로그인 및 세션 생성 확인
Apple 로그인이 제대로 작동했는지 확인하려면, Parse 대시보드를 확인하고 새로운 사용자 (Apple 인증 데이터가 다른 사용자에 속하지 않는 경우)와 함께 Apple authData 매개변수를 포함하고 있는지 확인할 수 있습니다.

대시보드에서 유효한 세션이 생성되었는지 확인할 수도 있으며, 해당 사용자 객체에 대한 포인터를 포함하고 있습니다.

4 - 기존 사용자를 Apple 로그인에 연결하기
또 다른 linkWith 가능한 사용법은 기존 사용자를 다른 인증 제공자, 이 경우에는 Apple과 연결하는 것입니다. linkWith를 호출하는 이 기능을 추가하세요. UserLogIn에서 했던 것과 같은 방식으로 당신의 HelloUser 컴포넌트나 직접 홈 화면에 추가하세요. 여기서 유일한 차이점은 빈 Parse.User에서 메서드를 호출하는 대신, 로그인한 사용자 객체에서 사용할 것이라는 점입니다.
1 const doUserLinkApple = async function (): Promise<boolean> {
2 try {
3 let response: object = {};
4 let appleId: string = '';
5 let appleToken: string = '';
6 if (Platform.OS === 'ios') {
7 // Performs login request requesting user email
8 response = await appleAuth.performRequest({
9 requestedOperation: appleAuth.Operation.LOGIN,
10 requestedScopes: [appleAuth.Scope.EMAIL],
11 });
12 // On iOS, user ID and email are easily retrieved from request
13 appleId = response.user;
14 appleToken = response.identityToken;
15 } else if (Platform.OS === 'android') {
16 // Configure the request
17 appleAuthAndroid.configure({
18 // The Service ID you registered with Apple
19 clientId: 'YOUR_SERVICE_ID',
20 // Return URL added to your Apple dev console
21 redirectUri: 'YOUR_SERVICE_URL',
22 responseType: appleAuthAndroid.ResponseType.ALL,
23 scope: appleAuthAndroid.Scope.ALL,
24 });
25 response = await appleAuthAndroid.signIn();
26 // Decode user ID and email from token returned from Apple,
27 // this is a common workaround for Apple sign-in via web API
28 const decodedIdToken: object = jwt_decode(response.id_token);
29 appleId = decodedIdToken.sub;
30 appleToken = response.id_token;
31 }
32 // Format authData to provide correctly for Apple linkWith on Parse
33 const authData: object = {
34 id: appleId,
35 token: appleToken,
36 };
37 let currentUser: Parse.User = await Parse.User.currentAsync();
38 // Link user with his Apple Credentials
39 return await currentUser
40 .linkWith('apple', {
41 authData: authData,
42 })
43 .then(async (loggedInUser: Parse.User) => {
44 // logIn returns the corresponding ParseUser object
45 Alert.alert(
46 'Success!',
47 `User ${loggedInUser.get(
48 'username',
49 )} has successfully linked his Apple account!`,
50 );
51 // To verify that this is in fact the current user, currentAsync can be used
52 currentUser = await Parse.User.currentAsync();
53 console.log(loggedInUser === currentUser);
54 return true;
55 })
56 .catch(async (error: object) => {
57 // Error can be caused by wrong parameters or lack of Internet connection
58 Alert.alert('Error!', error.message);
59 return false;
60 });
61 } catch (error: any) {
62 // Error can be caused by wrong parameters or lack of Internet connection
63 Alert.alert('Error!', error);
64 return false;
65 }
66 };이 기능을 Apple 버튼 onPress 매개변수에 할당하세요. 새로운 기능을 테스트하고, Parse.User 객체의 authData 값이 새로운 인증 제공자 데이터로 업데이트될 것임을 주의하세요. 사용자가 실제로 Parse 서버 대시보드에서 업데이트되었는지 확인하세요.

결론
이 가이드의 끝에서, Apple Sign-in을 사용하여 React Native에서 Parse 사용자에게 로그인, 가입 또는 기존 사용자를 연결하는 방법을 배웠습니다. react-native-apple-authentication을 사용했습니다. 다음 가이드에서는 유용한 사용자 쿼리를 수행하는 방법을 보여드리겠습니다.