우리가 앱을 사용할 때 로그인을 하고 서비스 이용하다가 앱을 나가고 다시 들어왔을 때
로그인 된 상태를 본적이 있는가?
아니면 웹에서 로그인 상태 유지 (자동 로그인)을 선택하고 로그인 하고 나갔다가 들어와도 로그인 경험을 한적이 있다면 앱에서도 그 기능을 하고 있다고 보면 된다.
그러면 React Native에서는 어떻게 사용자 로그인 상태를 유지할까?
React Native Authentication works
React Native에서 사용자가 로그인을 하면 어떻게 로그인 상태를 유지를 알기 위해서는 우선 어떻게 사용자 인증을 하는 지에 대한 흐름을 알아본다.
1. RN에서 서버로 인증 데이터를 보내면 서버는 서버만 아는 private key를 토큰의 형태로 만든 후 반환한다.
2. RN은 storage에 토큰을 저장한다.
3. RN이 서버에 보호된 필요한 리소스가 있을 경우 토큰과 함께 서버에 전달한다.
4. 서버는 RN에서 보낸 토큰이 유효한 토큰인지 판단 후 유효한 토큰이면 알맞은 데이터를 반환한다.
이처럼 사용자 인증에 필요한 모든 정보는 토큰 자체에 포함한다.
그러면 RN에서 토큰을 어떻게 저장해야할까?
토큰 값은 디바이스에 저장되어 관리해야한다. 보통 RN은 Component의 데이터의 State를 중앙 집중적으로 관리하기 위해 Redux storage에 데이터를 저장하여 사용하지만, Redux에 저장해놓으면 메모레이에 저장되기 때문에 앱이 다시 시작 될 때 저장 된 값이 날라가기 때문이다. 그래서 앱이 꺼져도 써야하는 데이터의 경우는 디바이스 자체에 저장되어야 한다.
RN에서는 아래 방식을 사용하여 저장 할 수 있고 이에 따라 로그인 상태를 유지하고 인증을 구현 할 수 있다.
1. KeyChain
2. AsyncSTorage
3. react-native-mmkv
KeyChain
Keychain은 Apple에서 제공하는 보안 프레임워크로 디바이스 안에 암호화된 데이터 공간을 의미하며 사용자는 암호화된 공간에 데이터를 안전하게 보관할 수 있다.
iOS뿐만 아니라 다른 플랫폼은 다음 과 같이 키 저장소 플랫폼에 따른다.
- iOS : Keychain Services
- Android : Android Keystore
- Windows : Credential Management API
- OS X : Keychain Services
- Linux : 사용자가 설치해야 하는 libsecret
이처럼 암호 등 민감한 정보는 직접 정보를 암호화하여 관리하거나 각 플랫폼 별로 제공해주는 보안 프레임워크를 사용 할 수 있다.
react native에서는 react-native-keychian라이브러리를 사용하여 Keychain/Keystore를 사용 할 수 있다.
react-native-keychian
Usage
import * as Keychain from 'react-native-keychain';
async () => {
const username = 'zuck';
const password = 'poniesRgr8';
// Store the credentials
await Keychain.setGenericPassword(username, password);
try {
// Retrieve the credentials
const credentials = await Keychain.getGenericPassword();
if (credentials) {
console.log(
'Credentials successfully loaded for user ' + credentials.username
);
} else {
console.log('No credentials stored');
}
} catch (error) {
console.log("Keychain couldn't be accessed!", error);
}
await Keychain.resetGenericPassword();
};
react-native-keychain을 사용하여 username과 password를 저장하는 소스이다.
사용자 식별값과 패스워드를 저장하는 형태로 데이터 저장 시 keychian은 암호화하여 저정한다.
try {
const newAuthState = await authorize(configs.fusionauth);
console.log(newAuthState)
setAuthState({
hasLoggedInOnce: true,
...newAuthState
});
await Keychain.setGenericPassword('accessToken', newAuthState.accessToken);
} catch (error) {
Alert.alert('Failed to log in', error.message);
}
jwt 토큰 값도 저장 할 수 있습니다.
Keychain.setGenericPassword 에 Token 값을 저장하고 React Native Mobile App이 서버에 보호되는 필요한 리소스가 있을 경우 토큰과 함께 서버에 전달할 때 getGenericPassword 으로 Token 값을 가져와 서버에 전달 할 수 있다.
const getAccesstoken = async () => {
try {
// Retrieve the credentials
const credentials = await Keychain.getGenericPassword();
if (credentials) {
return credentials.password
} else {
console.log('No credentials stored');
}
} catch (error) {
console.log("Keychain couldn't be accessed!", error);
}
}
const getUser = async () => {
try {
const access_token = await getAccesstoken();
if (access_token !== null) {
fetch(configs.fusionauth.issuer+"/oauth2/userinfo", {
method: "GET",
headers: {
Authorization: "Bearer " + access_token,
},
})
.then((response) => response.json())
.then((json) => {
console.log(json);
setuserinfo(json);
})
.catch((error) => {
console.error(error);
});
}
} catch (e) {
console.log(e);
}
};
또한 인증 된 사용자의 정보를 가져올 땐 getUser 을 호출하는 함수를 만들고 저장소에서 액세스 토큰을 검색 한 다음 사용자 정보를 위해 엔드 포인트를 호출하여 가져올 수 있다.
AsyncStorage
디바이스에 저장하기 위해서는 Local Database에 저장하여야하는데 보통 유저 정보를 저장하거나 JWT 토큰 저장 또는 유저가 기록한 메모리를 저장 하는데 사용한다.
React Native에서 Local Database를 사용하기 위해서는 sqlite이나 AsyncStorage 등 이용하는 방법이 있다.
sqllite은 MySQL나 PostgreSQL와 같은 데이터베이스 관리 시스템이지만 서버가 아닌 응용 프로그램에 넣어 사용하는 데이터베이스이다.
AsyncStorage은 간단한 키-값쌍 데이터를 저장하는 데이터 저장소로 React Native에 내장된 기능이였지만 RN버전 0.59부터는 커뮤니티 라이브러리(@react-native-community/async-storage)로 분리되었다.Deprecated. Use one of the [community packages](https://reactnative.directory/?search=storage) instead.
2015 .5. 28 기준으로 확인해보니 react-native-community/async-storage도 더이상 지원하지 않고 react-native-async-storage/async-storage으로 지원한다.
sqlite 대신 AsyncStorage를 사용한 이유는 간단한 데이터를 저장하고 가져오는 기능을 구현하기 위해서는 AsyncStorage의 성능이 더 좋기 때문이다.
하지만 AsyncStorage은 KeyChain과 달리 저장 할 데이터를 암호화 하여 저장하지 않기 때문에 웹에서 LocalStorage에 저장하는 정보 처럼 jwt 토큰을 저장하거나 마지막으로 접속한 시간 등 민감하지 않는 정보만 저장하는 것이 좋다.
AsyncStorage은 setItem getItem 으로 데이터를 저장하거나 가져올 수 있다.
react-native-mmkv
react-native-mmkv은 react-native-async-storage과 마찬가지로 storage를 저장하는 패키지로 해당 패키지 빌더의 주장에 따르면 asyncStorage보다 30배는 빠른다고 한다.
set
//string
const storeData = async (value) => {
try {
await AsyncStorage.setItem('@storage_Key', value)
} catch (e) {
// saving error
}
}
//object
const storeData = async (value) => {
try {
const jsonValue = JSON.stringify(value)
await AsyncStorage.setItem('@storage_Key', jsonValue)
} catch (e) {
// saving error
}
}
get
//string
const getData = async () => {
try {
const value = await AsyncStorage.getItem('@storage_Key')
if(value !== null) {
// value previously stored
}
} catch(e) {
// error reading value
}
}
//object
const getData = async () => {
try {
const jsonValue = await AsyncStorage.getItem('@storage_Key')
return jsonValue != null ? JSON.parse(jsonValue) : null;
} catch(e) {
// error reading value
}
}
Head over to documentation to learn more.
사용 방법은 아래와 같다.
set
import { MMKV } from 'react-native-mmkv';
MMKV.set('user.name', 'Marc')
MMKV.set('user.age', 20)
MMKV.set('is-mmkv-fast-asf', true)
get
import { MMKV } from 'react-native-mmkv';
const username = MMKV.getString('user.name') // 'Marc'
const age = MMKV.getNumber('user.age') // 20
const isMmkvFastAsf = MMKV.getBoolean('is-mmkv-fast-asf') // true
const keys = MMKV.getAllKeys() // ['user.name', 'user.age', 'is-mmkv-fast-asf']
delete
import { MMKV } from 'react-native-mmkv';
MMKV.delete('user.name')
만약 사용자 정보를 저장한다면 아래와 같이 작업 할 수 있다.
import { MMKV } from 'react-native-mmkv';
const user = {
username: 'Marc',
age: 20
}
MMKV.set('user', JSON.stringify(user))
const jsonUser = MMKV.getString('user') // { 'username': 'Marc', 'age': 20 }
const userObject = JSON.parse(jsonUser)
이처럼 React Native은 여러 방식으로 인증 할 데이터를 저장할 수 있고 이에 따라 자동 인증을 구현 할 수 있다.
만일 아이디와 패스워드를 저장한다면 민감한 정보를 저자하기 때문에 KeyChain으로 진행하는 것이 좋고 그게 아니라면 async-storage나 react-native-mmkv 등 localStorage에 토큰 값을 저장하여 가져 오는 것이 좋다는 판단이다.
Firebase 알아보기
파이어 베이스는 공유된 iOS 키 체인으로 앱 간 인증 사용 설정 뿐만아니라
Google, Facebook, Apple, Twitter, GitHub 등 다양한 간편 로그인도 제공해주고 있습니다.
또한, 파이어 베이스의 경우는 Naver, KaKao의 간편 로그인을 지원하고 있지 않지만 새 OAuth ID 공급업체(IdP) 구성을 추가하려면 projects.defaultSupportedIdpConfigs 엔드포인트에 새 구성을 게시하거나 Firebase 맞춤 토큰으로 커스텀하여 간편 로그인을 추가 할 수 있습니다.
[참고 자료]
- react native - user authentication flow
url : https://velog.io/@tera_geniel/react-native-user-authentication-flow
- Using React-Native-KeyChain to Secure Mobile App Credentials
url : https://blog.bitsrc.io/using-keychain-in-react-native-and-keeping-the-app-session-alive-ff8f8850119c
- react native - auth, 자동 로그인, 자동로그아웃
url : https://wordbe.tistory.com/entry/React-Native-Auth-자동로그인-자동로그아웃\
- react-native의-asyncstorage-최적화
url : https://sendbird.com/ko/blog/react-native의-asyncstorage-최적화
- OAuth로 React Native 보안
url : https://ichi.pro/ko/oauthlo-react-native-boan-129729128952776
https://github.com/mCodex/react-native-sensitive-info
- Firebase 인증에 사용할 OAuth ID 공급업체를 프로그래매틱 방식으로 구성
url : https://firebase.google.com/docs/projects/provisioning/configure-oauth?hl=ko
- 공유된 iOS 키체인으로 앱 간 인증 사용 설정
url : https://firebase.google.com/docs/auth/ios/single-sign-on?hl=ko
'IT > 기록' 카테고리의 다른 글
초기 react-native 프로젝트 생성 후 실행 시 발생한 오류! (0) | 2021.06.02 |
---|---|
NodeJS에서 엑셀 파일 읽고 쓰기! #1 (0) | 2021.06.01 |
머신러닝 02. (0) | 2020.09.15 |
머신러닝. 01 (0) | 2020.09.15 |
고객 세분화 (0) | 2020.09.15 |