JiSoo's Devlog
[React Native] 사용자 인증 본문
모바일 기기에서 앱을 실행하고 인증을 하기 위해서는 백엔드 API가 필요
→ 사용자가 입력한 이메일 및 비밀번호의 유효성을 백엔드에서 검사해야 하기 때문에
사용자 데이터는 모바일 기기가 아니라 벡엔드에 있는 데이터베이스에 저장되기 때문에 기기에서 작업 수행 불가
사용자가 인증 양식을 작성 후 이메일, 비밀번호를 입력하면 크리덴셜이 HTTP 요청과 함께 백엔드 API로 전송되고
백엔드에서 해당 크리덴셜의 유효성이 검사된다
사용자가 처음 생성된 경우 → 유효한 이메일 주소인지, 비밀번호가 최소 길이를 충족하는지 확인 후 사용자 생성
이미 생성된 사용자의 경우 → 크리덴셜이 올바른지 확인
크리덴셜이 올바르다면 인증 토큰이 생성된다
이 토큰은 문자열로 되어있는데 모바일 기기로 다시 전송된다
토큰이 중요한 이유는!
토큰이 있어야 유효성 검사에 성공했다는 것을 알 수 있고
백엔드의 다른 리소스 혹은 인증을 필요로 하는 API의 다른 엔드포인트에 필요하기 때문
토큰이 기기에 저장되면 로그인했음을 증명할 수 있고 향후 HTTP 요청 발생 시 리소스를 잠재적으로 보호할 수 있다
→ API 엔드포인트 보안 가능
Firebase에 활성화한 인증 기능 사용 방법
- Firebase SDK를 코드에 추가해 사용
- Firebase REST API를 사용해 Firebase에서 제공하는 특성 API 엔드포인트에 요청을 보내서 사용자를 생성하고 로그인하게 하는 방법
User-Authentication - 프로젝트 설정 - 일반 - Firebase Console (google.com)
** navigate 대신 replace 호출하면 뒤로 가기 버튼 보이지 않게 하고 다른 화면으로 이동 가능
auth.js
export async function createUser(email, password) {
const response = await axios.post(
"https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=" + API_KEY,
{
email: email,
password: password,
returnSecureToken: true,
}
);
}
SignupScreen.js
function SignupScreen() {
const [isAuthenticating, setIsAuthenticating] = useState(false);
async function signupHandler({ email, password }) {
setIsAuthenticating(true);
await createUser(email, password);
setIsAuthenticating(false);
}
if (isAuthenticating) {
return <LoadingOverlay message="Creating user..." />;
}
return <AuthContent onAuthenticate={signupHandler} />;
}
에러 핸들링
try {
await createUser(email, password);
} catch (error) {
Alert.alert(
"Authentication failed!",
"Could not create user, please check your input and try again later."
);
}
애플리케이션의 다른 부분에서 필요로 하는 데이터를 저장하려 할 때 Redux나 React Context가 좋은 선택지
const authCtx = useContext(AuthContext);
async function loginHandler({ email, password }) {
setIsAuthenticating(true);
try {
const token = await login(email, password);
authCtx.authenticate(token);
} catch (error) {
이런 식으로 로그인 화면에서 토큰을 얻어 콘텍스트에 설정하면 콘텍스트에 유효한 토큰이 생기고 사용자 인증도 가능
인증 상태에 따라 화면 전환하기 → 라우트 방지 혹은 화면 보호
특정 조건이 충족되지 않는 한 특정 화면으로의 전환을 막아야 한다
function Navigation() {
const authCtx = useContext(AuthContext);
return (
<NavigationContainer>
{!authCtx.isAuthenticated && <AuthStack />}
{authCtx.isAuthenticated && <AuthenticatedStack />}
</NavigationContainer>
);
}
화면 전환은 내비게이션 스택으로 전환할 때 자동으로 일어난다!!
내비게이터를 호출하거나 대체할 필요 없다
호출하는 대신 내비게이션 스택을 새로이 활성화된 스택에 있는 메인 화면으로 교체해 주면 자동으로 전환
로그아웃
AuthContext를 사용해서 authCtx.logout 함수로 로그아웃 함수를 호출
로그아웃 버튼을 누르면 토큰이 지워지면서 콘텍스트가 업데이트되고 다른 페이지의 스택을 다시 로딩하게 된다
토큰을 사용해 백엔드에서 보호되는 리소스에 액세스도 가능
인증된 사용자만 액세스 가능한 특정 엔드포인트가 필요하다
우리는 사용자를 로그인하지만 백엔드에서는 인증된 사용자와 데이터 사이에 연결이 존재하지 않는 이유는
백엔드 API가 무상태성이라서 그렇다
Firebase는 사용자의 로그인 정보를 저장하지 않기 때문제 토큰을 얻고 액세스 권한을 부여하거나 보호된 엔드포인트를 액세스 할 권한을 얻는다
그렇게 하기 위해 엔드포인트를 보호해야 하는데 Firebase에서는 읽기 등의 규칙을 변경하면 된다
{
"rules": {
".read": "auth.uid != null",
".write": "auth.uid != null"
}
}
토큰은 인증된 사용자가 보낸 요청인지 확인하기 위한 목적으로 API에서 사용되기도 한다
일반적으로 REST API는 그런 정보를 저장하지 않고 임의의 앱 사용자가 인증되었는지를 알지 못하기 때문이다
대신 토큰을 보호 중인 리소스에 전송할 요청과 함께 보내야 한다
토큰이 있어야 액세스할 수 있기에 프론트에서 토큰을 관리하고 사용자 인증 여부를 확인하기 위해서만이 아닌 발신되는 HTTP 요청에도 토큰을 첨부하는 것
useEffect(() => {
axios
.get(
"https://user-authentication-a265e-default-rtdb.firebaseio.com/message.json?auth=" +
token
)
.then((response) => {
setFetchedMessage(response.data);
});
}, [token]);
토큰과 인증 상태는 콘텍스트, 즉 메모리에만 저장되기 때문에 앱이 닫히고 다시 열릴 경우 해당 상태를 잃게 된다
메모리뿐만 아니라 장치에도 토큰을 저장하고 싶다면 서드 파티 패키지 사용
React Native AsyncStorage
@react-native-async-storage 패키지 등등
이 패키지를 설치하면 데이터를 장치에 저장 가능
npm i @react-native-async-storage/async-storage
AsyncStorage.setItem("token", token);
**토큰 만료
콘텍스트에서 관리하고 기기에 저장하는 토큰은 만료될 수 있다
백엔드에 따라 달라지겠지만 Firebase는 토큰에 1시간 타이머가 있다
1. 1시간 후에 사용자 자동 로그아웃시키기
setTimeout()으로 설정해서 사용자를 자동 로그아웃시키는 타이머 설정
2. 토큰을 새로 고침해 새로운 auth 토큰 받기
Firebase가 제공하는 특정 authAPI 엔드포인트를 통해 설정 가능
auth 토큰을 받을 때 refresh 토큰도 받게 된다
응답의 resfreshToken 필드는 새 auth 토큰을 얻기 위해 refresh tokenAPI 엔드포인트로 전송할 수 있는 토큰을 가지고 있다
https://firebase.google.com/docs/reference/rest/auth#section-refresh-token
'App > React Native' 카테고리의 다른 글
[React Native] 지출 추적 앱 (0) | 2024.05.13 |
---|---|
[React Native] React Native 내비게이션 (0) | 2024.05.08 |
[React Native] 호환 가능한 사용자 인터페이스 구축 (0) | 2024.04.30 |
[React Native] 미니 게임 앱 (0) | 2024.04.29 |
[React Native] 앱 디버깅 (0) | 2024.04.26 |