맨땅에 코딩
RE:BORN Frontend - React Native Naver Login 구현 본문
안녕하세요 오랜만에 산학 개발 일지? 를 작성하러 왔습니다.
한창 RE:BORN 프로젝트 리뉴얼을 준비 중인데요, 리뉴얼 된 버전에서는 네이버, 카카오, 구글 이렇게 3가지의 소셜 로그인을 구현할 계획입니다.
그래서 이전에 산학프로젝트에서 네이버 소셜 로그인 했던 걸 들쳐내봅니다...
지금 다시 보면 코드 진짜 더럽다고 생각할텐데.. (이땐 코드를 이쁘게 짜는거고 뭐고 그냥 급하게 호다닥 했습니다..)
아무튼 어떻게 구현했는지 알아봅시다.
먼저, 구글링을 통해 탐색하던 중
https://github.com/crossplatformkorea/react-native-naver-login
GitHub - crossplatformkorea/react-native-naver-login: 리엑트 네이티브 네이버 로그인 라이브러리
리엑트 네이티브 네이버 로그인 라이브러리. Contribute to crossplatformkorea/react-native-naver-login development by creating an account on GitHub.
github.com
참고할만한 깃허브 소스를 찾아냈고, 이 소스를 활용하여 구현해 보았습니다.
일단 다음 패키지 install이 필요합니다.
npm i @react-native-seoul/naver-login
그리고 다음과 같이 코드를 작성해주었습니다.
LoginScreen.js
import React, { useState } from "react";
import { View, Text, StyleSheet, Image, TouchableOpacity } from "react-native";
import axios from "axios";
import { buttonStyles } from "../../components";
import { colors } from "../../theme";
import NaverLogin from "@react-native-seoul/naver-login";
import { useAccessToken, useDeviceToken } from "../../context/AccessTokenContext";
const consumerKey = "";
const consumerSecret = "";
const appName = "Hello";
const serviceUrlScheme = "navertest";
const LoginScreen = ({ navigation: { navigate } }) => {
const [success, setSuccessResponse] = useState();
const [failure, setFailureResponse] = useState();
const [getProfileRes, setGetProfileRes] = useState();
const [nickname, setNickname] = useState("");
const [email, setEmail] = useState("");
const { setAccessToken } = useAccessToken();
const { deviceToken } = useDeviceToken();
const sendUserProfileToServer = async (accessToken) => {
try {
const profileResult = await NaverLogin.getProfile(accessToken);
if (profileResult) {
const { nickname, email } = profileResult.response;
const username = "{naver}" + email.split("@")[0];
const provider = "naver";
setNickname(nickname);
setEmail(email);
setGetProfileRes(profileResult);
const userData = {
email,
username,
nickname,
provider,
deviceToken,
};
axios
.post("http://reborn.persi0815.site/token/generate", userData)
.then((response) => {
const { accessToken, signIn } = response.data.result;
setAccessToken(accessToken);
if (signIn === "wasUser") {
navigate("Tabs", { screen: "main" });
} else navigate("IntroStack", { screen: "Intro" });
})
.catch((error) => {
console.error("ERROR", error);
if (error.response) {
// 요청이 이루어졌으나 서버가 2xx 이외의 상태 코드로 응답
console.error("Error Response:", error.response.data);
console.error("Status:", error.response.status);
console.error("Headers:", error.response.headers);
} else if (error.request) {
// 요청이 이루어졌으나 응답을 받지 못함
console.error("Error Request:", error.request);
} else {
// 요청을 만들 때 문제가 발생함
console.error("Error Message:", error.message);
}
});
}
} catch (e) {
setGetProfileRes(undefined);
setNickname("");
setEmail("");
}
};
const login = async () => {
try {
const { failureResponse, successResponse } = await NaverLogin.login({
appName,
consumerKey,
consumerSecret,
serviceUrlScheme,
});
setSuccessResponse(successResponse);
setFailureResponse(failureResponse);
if (successResponse) {
setAccessToken(successResponse.accessToken);
sendUserProfileToServer(successResponse.accessToken);
}
} catch (error) {
console.error("로그인 에러:", error);
}
};
return (
<View style={styles.container}>
<View style={styles.introContainer}>
<Text style={styles.introTitle}>
PET <Text style={{ color: colors.palette.Yellow }}>RE</Text>BORN,
{"\n"}로그인 하기
</Text>
</View>
<View style={styles.contentContainer}>
<Image
style={{ width: "90%", height: "83%", bottom: "8%", resizeMode: 'center' }}
source={require("../../Assets/icons/app_icon22.png")}
/>
<View style={styles.buttonContainer}>
<TouchableOpacity style={buttonStyles.buttonLogin} onPress={login}>
<View style={styles.buttonContent}>
<Image
source={require("../../Assets/icons/naver_logo.png")}
style={styles.naverLogo}
/>
<Text style={styles.buttonText}>네이버 아이디로 로그인 </Text>
</View>
</TouchableOpacity>
</View>
</View>
</View>
);
};
export default LoginScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.palette.White,
},
introContainer: {
marginTop: "10%",
},
contentContainer: {
alignItems: "center",
},
introTitle: {
fontSize: 45,
textAlign: "left",
paddingLeft: "5%",
fontFamily: "Poppins-SemiBold",
color: colors.palette.BrownDark,
},
buttonContainer: {
position: "absolute",
top: "70%",
bottom: "20%",
},
buttonContent: {
flexDirection: "row",
alignItems: "center",
},
naverLogo: {
width: "10%",
height: "100%",
marginRight: "5%",
},
buttonText: {
textAlign: "center",
color: colors.palette.White,
fontFamily: "Poppins-Medium",
fontSize: 14,
},
});
로직을 간단하게 설명하자면 다음과 같습니다.
1. 네이버 로그인 처리 (login 함수)
- @react-native-seoul/naver-login 패키지를 사용하여 로그인 요청을 보냄
- 로그인 성공 시 successResponse.accessToken을 useAccessToken의 setAccessToken을 통해 저장
- 이후 sendUserProfileToServer 함수를 호출하여 사용자 정보를 서버에 전송
2. 네이버 프로필 정보 가져오기 (sendUserProfileToServer 함수)
- NaverLogin.getProfile(accessToken)을 사용하여 프로필 정보를 가져옴
- 사용자 정보(닉네임, 이메일)를 상태 변수(nickname, email)에 저장
- 백엔드에 POST 요청을 보내 사용자 정보를 저장 및 처리
- 응답을 바탕으로 Tabs/main 또는 IntroStack/Intro 화면으로 이동
3. 에러 핸들링
- 로그인 실패 시 failureResponse에 저장
- 서버 응답 실패 시 catch 문을 통해 에러 상세 정보를 출력
근데 뭐, 코드가 생각 보다 더러울 줄 알았는데, 급하게 한 것 치고는 나쁘지 않은 것 같다.
활용할 소스가 제대로 잘 되어있어서 그랬는지..
이번에 리뉴얼 할때는 3가지의 소셜 로그인이 가능하도록 구현해야하는데, 네이버 소셜 로그인을 구현했던 경험을 토대로
잘 구현이 되길 바랄 뿐...!
고럼 이만~
'KAU 2024 (3학년) > 산학프로젝트' 카테고리의 다른 글
RE:BORN Frontend - React Native 폰트 적용하기 (0) | 2024.12.02 |
---|---|
RE:BORN Frontend - React Native 환경 변수 설정하기 (0) | 2024.06.26 |
산학프로젝트 3학년 팀플의 꽃 - 'RE:BORN' (4) | 2024.06.23 |
산학프로젝트 3학년 팀플의 꽃 - 과목 소개 및 수강 후기 (0) | 2024.06.22 |
RE:BORN Backend - AI 서버(Flask) AWS 설정(EC2, Elastic IP) (0) | 2024.06.19 |