인사말
안녕하세요 무너발이다.
오늘은 에버핏 개발중 비밀번호 찾기 , 변경을 구현하려고 합니다.
이미 휴대폰인증은 회원가입 등에서 만들어두었지만 저도 스스로 대충만들었다고 느꼈고 팀장님도 맘에 안드신다하여
수정해서 기획하고 적용해보았습니다.
그냥 인증만하려고한다면 비교적간단하지만... 실 서비스라고 생각하면 복잡해지는군요 !
1탄은 요구사항 정의, 레이아웃 제작만 있고 2탄에서 서버, 액티비티 코드가 나옵니다
네이버의 비밀번호 찾기 로직을 참고하여 제작하였음
1. 요구사항, 기능 정의
1)3단계의 동작으로 만든다
- 아이디 입력 및 확인 ( 비밀번호 찾기이므로 아이디는 안다는 가정)
- 휴대전화번호 본인인증
- 비밀번호 변경
2) 아이디 입력 및 확인
- 서버 요청 전 입력한 아이디 유효성검사
- 서버에서는 아이디 유무 확인 후 결과값 리턴
- 아이디가 존재하지 않으면 Toast 로 알림
- 아이디가 존재하면 다음화면으로 이동 (Intent에 인증성공한 아이디를함께 전달)
3) 휴대전화번호 본인인증
- 본인인증은 하루 5회 제한, 인증은 5분간유효, 재전송 대기 10초
- 서버요청 전 입력한 휴대전화번호 유효성검사
- 인증번호 전송요청시 아이디,휴대전화번호를 같이 서버에 전달
- 서버에서는 아이디,휴대전화번호가 일치하는 사용자 유무 확인 후 없을시 false 반환
- 사용자 존재하면 인증번호 난수 생성 -> cool sms api 이용 휴대전화번호로 인증번호 전송
( 그날 보낸 인증의 횟수를 count 하여 6회 이상이면 인증횟수 초과 반환 )
- 인증번호는 db에 저장 ( 하단 db 테이블 참조)
- 사용자에게는 인증번호 db의 인증 id를 반환 하여 인증번호 제출시 최신 인증id 로 요청하도록
처음에는 여러 블로그글처럼 인증요청시 반환값에 인증번호를 같이 주는것도 생각해보았지만 디테일한 보안은 모르지만
클라이언트에 인증번호를 같이 전달해준다는게 말이 안된다고 느껴졌다. 충분히 조작 가능할것같다 그래서 인증번호 검사도 서버에서 처리해주기로하였다.
서버에서 인증 5분간 유효는 어떤식으로 구현해야할지 몰라 검색해보았다.
첫번째 방법은 db에 인증번호, 인증id, 인증번호 요청시간을 저장해 5분뒤에 인증을시도했을때 인증번호 요청시간과 비교하여 인증번호가 일치하여도 인증만료를 반환
두번째 방법은 db를 5분뒤에 만료되는 튜플로 만드는것 ( mysql도 기능이있는지, 보통은 nosql을 사용한다고 하는데 나는 써본적이없다.)
이번주까지 완료해야하는것이라 redis를 사용해보는건 나중으로 미루고 하루 5회 제한을 만들기위해서 첫번째 방법을 선택했다.
=> 클라이언트에 타이머를 두어서 5분간만 요청을 보낼수있게 변경하였다.
4) 비밀번호 변경
- 입력한 비밀번호 유효성검사
- 비밀번호, 비밀번호 확인 일치여부 확인
- 비밀번호 변경버튼 클릭시에도 재검사
- 서버에서 비밀번호 db 변경
- 성공유무 반환
- 로그인 화면으로 이동 (dialog 확인 후 )
그리고 인증번호전송, 비밀번호 변경화면에서 뒤로가기시 이전화면으로 이동하나 다음화면 이동시 기존의 입력정보는 모두 사라지게 만들고 loginActivity를 singleTask로하여 마지막 인증후 loginActivity이동시 중간 activity가 모두 사라지게 만들것이다.
2. 레이아웃 구현
레이아웃 xml 파일 제작
xml 부터 모두 만들었다.
아이디입력 xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.accountUi.RegisterActivity"
tools:visibility="visible">
<ImageView
android:id="@+id/btnBack"
android:layout_width="34dp"
android:layout_height="36dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="5dp"
android:src="@drawable/baseline_keyboard_backspace_24"
app:layout_constraintBottom_toTopOf="@+id/text_register_pageName"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_register_pageName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:fontFamily="@font/notosanskrextrabold"
android:text="비밀번호 변경"
android:textColor="@color/black"
android:textSize="24sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/img_register_backButton" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:background="@drawable/edit_text_border"
android:gravity="center"
>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="1. 아이디 입력"
android:layout_weight="1"
android:gravity="center"
android:fontFamily="@font/notosanskrregular"
android:textColor="@color/blue"
>
</TextView>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="2. 전화번호 인증"
android:layout_weight="1"
android:gravity="center"
android:fontFamily="@font/notosanskrregular"
>
</TextView>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="3. 비밀번호 변경"
android:layout_weight="1"
android:gravity="center"
android:fontFamily="@font/notosanskrregular"
>
</TextView>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:layout_marginTop="25dp"
android:layout_marginBottom="25dp"
android:text="비밀번호를 찾고자 하는 아이디를 입력해주세요"
android:textColor="@color/black"
android:fontFamily="@font/notosanskrbold"
android:gravity="center"
/>
<TextView
android:id="@+id/textView_register_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:fontFamily="@font/notosanskrbold"
android:text="아이디"
android:textColor="@color/black"
android:textSize="14sp" />
<EditText
android:id="@+id/editId"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:background="@drawable/edit_text_border"
android:focusable="true"
android:focusableInTouchMode="true"
android:hint="아이디를 입력해주세요"
android:inputType="text"
android:textSize="14sp" />
<TextView
android:id="@+id/text_register_validName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:text="이름을 확인해주세요"
android:textColor="@color/red"
android:visibility="invisible" />
<Button
android:id="@+id/btnNext"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginStart="25dp"
android:layout_marginEnd="25dp"
android:layout_marginBottom="20dp"
android:background="@color/blue"
android:fontFamily="@font/notosanskrbold"
android:text="다음"
android:textColor="@color/white"
android:textSize="20sp">
</Button>
</LinearLayout>

휴대폰 번호인증 xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:visibility="visible"
tools:context=".activity.accountUi.findPw.FindPwVerifyPhoneNumberActivity">
<ImageView
android:id="@+id/btnBack"
android:layout_width="34dp"
android:layout_height="36dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="5dp"
android:src="@drawable/baseline_keyboard_backspace_24"
app:layout_constraintBottom_toTopOf="@+id/text_register_pageName"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_register_pageName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:fontFamily="@font/notosanskrextrabold"
android:text="비밀번호 변경"
android:textColor="@color/black"
android:textSize="24sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/img_register_backButton" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:background="@drawable/edit_text_border"
android:gravity="center"
>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="1. 아이디 입력"
android:layout_weight="1"
android:gravity="center"
android:fontFamily="@font/notosanskrregular"
>
</TextView>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="2. 전화번호 인증"
android:layout_weight="1"
android:gravity="center"
android:fontFamily="@font/notosanskrregular"
android:textColor="@color/blue"
>
</TextView>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="3. 비밀번호 변경"
android:layout_weight="1"
android:gravity="center"
android:fontFamily="@font/notosanskrregular"
>
</TextView>
</LinearLayout>
<TextView
android:id="@+id/text_register_validName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:text="회원정보에 등록된 휴대전화번호를 입력해주세요."
android:fontFamily="@font/notosanskrbold"
android:textColor="@color/black"
android:gravity="center"
/>
<TextView
android:id="@+id/textView_register_phoneNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:fontFamily="@font/notosanskrbold"
android:text="휴대전화번호"
android:textColor="@color/black"
android:textSize="14sp" />
<LinearLayout
android:id="@+id/linear"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:orientation="horizontal">
<EditText
android:id="@+id/editPhoneNumber"
android:layout_width="250dp"
android:layout_height="48dp"
android:background="@drawable/edit_text_border"
android:focusable="true"
android:focusableInTouchMode="true"
android:hint="휴대전화번호를 입력해주세요."
android:inputType="number"
android:textSize="14sp" />
<Button
android:id="@+id/btnSendCode"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="인증번호 전송"
android:textSize="12sp" />
</LinearLayout>
<TextView
android:id="@+id/text_register_validPhoneNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:text="전화번호를 확인해주세요"
android:textColor="@color/red"
android:visibility="invisible" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:fontFamily="@font/notosanskrbold"
android:text="인증번호"
android:textColor="@color/black"
android:textSize="14sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:orientation="horizontal">
<EditText
android:id="@+id/editCode"
android:layout_width="250dp"
android:layout_height="48dp"
android:background="@drawable/edit_text_border"
android:focusable="true"
android:focusableInTouchMode="true"
android:hint="인증번호를 입력해주세요."
android:inputType="number"
android:textSize="14sp" />
<Button
android:id="@+id/btnConfirmCode"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="인증번호 확인"
android:textSize="12sp" />
</LinearLayout>
<TextView
android:id="@+id/textCodeWarning"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:text="인증번호를 확인해주세요"
android:textAlignment="textStart"
android:textColor="@color/red"
android:visibility="invisible" />
<Button
android:id="@+id/btnNextPage"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginStart="25dp"
android:layout_marginEnd="25dp"
android:layout_marginBottom="20dp"
android:background="@color/blue"
android:fontFamily="@font/notosanskrbold"
android:text="다음"
android:textColor="@color/white"
android:textSize="20sp">
</Button>
</LinearLayout>

비밀번호 변경화면 xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.accountUi.RegisterActivity"
tools:visibility="visible">
<ImageView
android:id="@+id/btnBack"
android:layout_width="34dp"
android:layout_height="36dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="5dp"
android:src="@drawable/baseline_keyboard_backspace_24"
app:layout_constraintBottom_toTopOf="@+id/text_register_pageName"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_register_pageName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:fontFamily="@font/notosanskrextrabold"
android:text="비밀번호 변경"
android:textColor="@color/black"
android:textSize="24sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/img_register_backButton" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:background="@drawable/edit_text_border"
android:gravity="center"
>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="1. 아이디 입력"
android:layout_weight="1"
android:gravity="center"
android:fontFamily="@font/notosanskrregular"
>
</TextView>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="2. 전화번호 인증"
android:layout_weight="1"
android:gravity="center"
android:fontFamily="@font/notosanskrregular"
>
</TextView>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="3. 비밀번호 변경"
android:layout_weight="1"
android:gravity="center"
android:fontFamily="@font/notosanskrregular"
android:textColor="@color/blue"
>
</TextView>
</LinearLayout>
<TextView
android:id="@+id/text_register_validName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:text="새로 사용할 비밀번호를 입력해주세요."
android:fontFamily="@font/notosanskrbold"
android:textColor="@color/black"
android:gravity="center"
/>
<TextView
android:id="@+id/textView_register_pw"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:fontFamily="@font/notosanskrbold"
android:text="비밀번호"
android:textColor="@color/black"
android:textSize="14sp" />
<EditText
android:id="@+id/editPw"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:background="@drawable/edit_text_border"
android:focusable="true"
android:focusableInTouchMode="true"
android:hint="영문,숫자 조합 8~16자"
android:inputType="textPassword"
android:textSize="14sp" />
<TextView
android:id="@+id/textPwWarning"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:text="비밀번호를 확인해주세요"
android:textColor="@color/red"
android:visibility="invisible" />
<TextView
android:id="@+id/textView_register_pwConfirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:fontFamily="@font/notosanskrbold"
android:text="비밀번호 확인"
android:textColor="@color/black"
android:textSize="14sp" />
<EditText
android:id="@+id/editPwConfirm"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:background="@drawable/edit_text_border"
android:focusable="true"
android:focusableInTouchMode="true"
android:hint="비밀번호를 한번 더 입력해주세요."
android:inputType="textPassword"
android:textSize="14sp" />
<TextView
android:id="@+id/textPwConfirmWarning"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:text="비밀번호가 일치하지 않습니다."
android:textColor="@color/red"
android:visibility="invisible" />
<Button
android:id="@+id/btnChangePw"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginStart="25dp"
android:layout_marginEnd="25dp"
android:layout_marginBottom="20dp"
android:background="#B5453E3E"
android:fontFamily="@font/notosanskrbold"
android:text="비밀번호 변경"
android:textColor="@color/white"
android:gravity="center"
android:textSize="20sp"></Button>
</LinearLayout>

액티비티, 서버 코드는 다음 글에서 계속 .....
사실 글을 쓰고있는 와중에도 리팩토링중이라 마무리를 못짓고 넘어갑니다 죄송해요.
완성은 했는데 너무 구려서 ... 다시 만드려고합니다 !