sms 인증(with파이어베이스)
파이어베이스를 활용하여
전화번호 sms 인증을 하려고 한다면
사전에 파이어베이스에
프로젝트 생성 및 설정이
되어 있어야 합니다.
※ 파이어베이스 인증 부분에서 '전화번호'를 추가하여야 합니다.
해당 포스팅에서는
사전 과정을 마친 이후에
진행을 합니다.
○ 안드로이드 환경 : SDK(안드로이드 API 21 이상), JDK(JDK 11이상), Gradle 빌드
1. 환경 설정
1-1. 파이어베이스 프로젝트에서 google-services.json 다운로드 받아
해당 프로젝트 루트 디렉터리에 추가.
1-2. 파이어베이스(Firebase) SDK 추가
프로젝트 수준의 build.gradle 파일에 플러그인을 종속 항목으로 추가
plugins {
// ...
// Add the dependency for the Google services Gradle plugin
id 'com.google.gms.google-services' version '4.4.2' apply false
}
모듈(앱 수준) build.gradle 파일에서 google-services 플러그인과 앱에서 사용할 Firebase SDK를 모두 추가
plugins {
id 'com.android.application'
// Add the Google services Gradle plugin
id 'com.google.gms.google-services'
...
}
dependencies {
// Import the Firebase BoM
implementation platform('com.google.firebase:firebase-bom:33.2.0')
// TODO: Add the dependencies for Firebase products you want to use
// When using the BoM, don't specify versions in Firebase dependencies
// https://firebase.google.com/docs/android/setup#available-libraries
// Add the dependency for the Firebase Authentication library
// When using the BoM, you don't specify versions in Firebase library dependencies
implementation("com.google.firebase:firebase-auth:16.0.4")
// Also add the dependency for the Google Play services library and specify its version
implementation("com.google.android.gms:play-services-auth:20.1.0")
}
그리고
디펜던시로 하나더 추가해야 해주어야 합니다.
(이유는 포스팅을 쭈욱 읽어나가다 보면 아시게 됩니다.)
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.30'
gradle sync 또는 빌드를 해주어 오류가 나는 지 확인해봅시다.
참고) 파이어베이스 SDK가 google-services.json 구성 값에 액세스할 수 있도록 하려면 구글 서비스 gradle 플러그인 필요.
2. 인증 로직 :
파이어베이스를 사용하여 인증된 사용자만 접속(로그인)할 수 있는 동작을 구현해보도록 하겠습니다.
절차) 전화번호 입력 -> 인증코드 전송 -> 인증코드 입력 -> 로그인
※로그인 후, 사용자 정보를 가져오는 것도 포함
2-1. 레이아웃 파일 작성
간단하게
전화번호 입력, 인증코드 입력
인증코드 전송 버튼, 로그인 버튼 생성
<EditText
android:id="@+id/phoneNumber"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="input your phone number"
android:textSize="70px"
android:inputType="phone"
android:textAlignment="center"
/>
<Button
android:id="@+id/phoneAuthBtn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:text="인증번호"
/>
<EditText
android:id="@+id/authNumber"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="input your auth number"
android:textSize="70px"
android:inputType="phone"
android:textAlignment="center"
/>
<Button
android:id="@+id/phoneLoginBtn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:text="로그인"
/>
2-2. 액티비티 파일에 텍스트 인풋, 버튼에 대한 로직 추가 :
private String verificationId;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_phone);
EditText phoneNumber = findViewById(R.id.phoneNumber);
EditText authNumber = findViewById(R.id.authNumber);
Button authNumberBtn = findViewById(R.id.phoneAuthBtn);
Button loginBtn = findViewById(R.id.phoneLoginBtn);
authNumberBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String str = phoneNumber.getText().toString();
Log.d("PhoneNumber", str);
sendAuthCode(str);
}
});
loginBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String code = authNumber.getText().toString();
verifyAuthCode(code);
}
});
}
//인증번호 요청
private void sendAuthCode(String phoneNumber) {
Log.d("PhoneNumber sendAuthCode", phoneNumber); //010-xxxx-xxxx
//phoneNumber trans e.164 format
String str_parseNumber;
try {
PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
Phonenumber.PhoneNumber parseNumber = phoneNumberUtil.parse(phoneNumber, "KR");
str_parseNumber = phoneNumberUtil.format(parseNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
Log.d("PhoneNumber trans", str_parseNumber); // +821012345678
} catch (NumberParseException e) {
Log.d("PhoneNumber trans error", e.getMessage());
throw new RuntimeException(e);
}
PhoneAuthOptions options = PhoneAuthOptions
.newBuilder(FirebaseAuth.getInstance())
.setPhoneNumber(str_parseNumber) //e.164
.setTimeout(60L, TimeUnit.SECONDS)
.setActivity(this)
.setCallbacks(phoneCallback)
.build();
PhoneAuthProvider.verifyPhoneNumber(options);
}
//인증번호 확인
private void verifyAuthCode(String code){
Log.d("PhoneNumber verifyAuthCode", code);
PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);
//로그인
signIn(credential);
}
//콜백
private PhoneAuthProvider.OnVerificationStateChangedCallbacks phoneCallback =
new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
@Override
public void onVerificationCompleted(@NonNull PhoneAuthCredential phoneAuthCredential) {
String code = phoneAuthCredential.getSmsCode();
if(code != null){
Log.d("PhoneNumber verification completed", code);
verifyAuthCode(code);
}
}
@Override
public void onVerificationFailed(@NonNull FirebaseException e) {
Log.d("PhoneNumber verification failed", e.getMessage());
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
@Override
public void onCodeSent(@NonNull String s, @NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken) {
super.onCodeSent(s, forceResendingToken);
verificationId = s;
Log.d("PhoneNumber onCodeSent", s + "/" + forceResendingToken.toString());
}
@Override
public void onCodeAutoRetrievalTimeOut(@NonNull String s) {
super.onCodeAutoRetrievalTimeOut(s);
}
};
private void signIn(PhoneAuthCredential credential){
FirebaseAuth.getInstance()
.signInWithCredential(credential)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
FirebaseUser user = task.getResult().getUser();
Log.d("PhoneNumber FirebaseUser", user.getPhoneNumber());
finish();
} else {
Toast.makeText(getApplicationContext(), task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
}
});
}
2-3. 입력한 전화번호로 인증코드 전송
PhoneAuthOptions options = PhoneAuthOptions
.newBuilder(FirebaseAuth.getInstance())
.setPhoneNumber(str_parseNumber) //Phone number to verify ※e.164
.setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this) // (optional) Activity for callback binding
// If no activity is passed, reCAPTCHA verification can not be used.
.setCallbacks(phoneCallback) // OnVerificationStateChangedCallbacks
.build();
PhoneAuthProvider.verifyPhoneNumber(options);
※ 파이어베이스 연동 시, 전화번호 형식은 E.164로 보내주어야 합니다.
(str_parseNumber 변수 확인)
PhoneAuthOptions options = PhoneAuthOptions
.newBuilder(FirebaseAuth.getInstance())
.setPhoneNumber(str_parseNumber) //e.164
.setTimeout(60L, TimeUnit.SECONDS)
.setActivity(this)
.setCallbacks(phoneCallback)
.build();
앞에서 그래들 디펜던시에 'libphonenumber'을 추가한 이유가 바로 이것 때문입니다.
해당 라이브러리를 사용하면
흔히 사용하는 전화번호(010-XXXX-XXXX) 형식을
파이어베이스가 요구하는 E.164형식(+8210XXXXXXXX)으로 간단하게 변환 가능합니다.
3. 인증 번호 확인 및 로그인 :
로그인 버튼을 누르게 되면 인증 번호 검증 후에 로그인이 진행되며,
이후 사용자 프로필 정보를 조회합니다.
//인증번호 확인
private void verifyAuthCode(String code){
Log.d("PhoneNumber verifyAuthCode", code);
PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);
//로그인
signIn(credential);
}
private void signIn(PhoneAuthCredential credential){
FirebaseAuth.getInstance()
.signInWithCredential(credential)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
FirebaseUser user = task.getResult().getUser();
Log.d("PhoneNumber FirebaseUser", user.getPhoneNumber());
Log.d("PhoneNumber FirebaseUser", String.valueOf(user));
finish();
} else {
Toast.makeText(getApplicationContext(), task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
}
});
}
※ verificationId : 해당 변수를 기준으로 파이어베이스 인증을 함.
4. 사용자 정보 가져오기 : 로그인한 사용자의 프로필 정보를 가져올 수 있습니다.
FirebaseAuth.getInstance()
.signInWithCredential(credential)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
//파이어베이스 사용자 객체를 가지고 옴
FirebaseUser user = task.getResult().getUser();
Log.d("PhoneNumber FirebaseUser", user.getPhoneNumber());
finish();
} else {
Toast.makeText(getApplicationContext(), task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
}
});
5. 구현동작 확인.
전화번호 및 인증번호 입력 창
전화번호 입력 후, 인증번호 클릭하면
reCAPTCHA verification
(파이어베이스 전화번호 인증 장점 :
로직 진행 과정에서 로봇 체크를 해줌)
task.isSuccessful() //true
user.getPhoneNumber() //+821122223333
로그인 성공하면 다음과 같은 사용자 정보 조회가 됩니다.
참고)
○ 인증이 안 된 경우는 다음과 같은 처리가 됩니다.
○ 전화번호 형식이 E.164가 아닌 경우
다음과 같이 오류 처리됩니다.
2024.08.27 - [스마트웹앱콘텐츠전문가/안드로이드] - 페이스북 로그인 연동
2024.08.27 - [스마트웹앱콘텐츠전문가/안드로이드] - 카카오 로그인 연동
2024.08.27 - [스마트웹앱콘텐츠전문가/안드로이드] - 네이버 로그인 연동(네아로)
2024.08.28 - [스마트웹앱콘텐츠전문가/안드로이드] - 구글 로그인 연동(with 파이어베이스)