본문 바로가기

앱 개발

[ Kotlin 앱 개발 ] 로그인 구현 #3 - Kotlin과 php, DB 연동

이전 포스팅에 이어 포스팅해보겠습니다.

 

[ Kotlin 앱 개발 ] 로그인 구현 #1 - 레이아웃 구성

이제 kotlin을 통해 본격적으로 앱 개발을 시작해볼 텐데요 가장 처음으로 생성할 것은 로그인 페이지를 만들고 가장 마지막 구현 포스팅 때 php와 MySQL을 만들어 회원정보를 담아보겠습니다. SQLite

seahippocampus.tistory.com

 

[ Kotlin 앱 개발 ] 로그인 구현 #2 - 액티비티 값 넘기기

이번에는 로그인 버튼을 눌렀을 때 입력한 값을 다음 화면으로 전송해주는 코드를 작성해 보겠습니다. 웹 개발 할 때 form 태그로 logincheck_php로 넘기는 것과 비슷합니다. php의 form태그에서도 각 in

seahippocampus.tistory.com

 

이젠 틀을 만들어놨던 액티비티들에 생명을 불어넣는 작업을 해보겠습니다.

 

현재 저는 안드로이드 스튜디오가 호스트 pc에 있고 DB와 웹 서버는 Virtualbox 가상머신에 설치되어 있습니다.

 

바로 이 DB와 연동해서 회원가입을 하거나 로그인을 할 때 이 DB에 추가하고 검증하고 하는 로직을 추가하겠습니다.

 

안드로이드와 DB를 연동하기 위해선 

 

안드로이드 > PHP > MySQL 의 과정을 거쳐야 합니다.

안드로이드 자체에서 MySQL로 접속하는 것을 막아놨기 때문입니다.

PHP와 MySQL 연결하는 건 웹 개발 때 하던 것과 동일하고,

이번에 신경써야할 것은 Kotlin과 PHP를 연결하는 것입니다.

 

APM 세팅

 

APM 세팅을 위해서 우선 Virtualbox의 칼리 리눅스에 우선 apache2를 설치해줍니다.

 

다 설치되있는 것 같다고 생각하지만 빠진 게 있을 수도 있다고 생각해서입니다.

 

아래 명령어로 php와 관련된 라이브러리도 설치합니다.

 

MySQL도 손쉽게 다루기 위해서 phpmyadmin도 설치해줍니다.

 

다 설치되었다면 명령어에

sudo vi /etc/apache2/apache.conf 를 입력해서

 

아래 내용을 입력해줍니다.

Include /etc/phpmyadmin/apache.conf

:wq를 입력하고 저장하고 나가줍니다.

 

웹 브라우저를 열고 phpmyadmin을 접속하니 잘 접속됩니다.

 

 

안드로이드 스튜디오 세팅

이제 APM 세팅이 다 되었으니

안드로이드 스튜디오를 켜줍니다。

 

인터넷 권한 선언을 위해서 volley 세팅을 해줄겁니다.

 

build.gradle 을 클릭해서 하단 dependencies 에 volley를 작성해줍니다.

 

implementation 'com.android.volley 까지 적어주면 자동완성이 아마 될 겁니다.

 

 

상단의 Sync now까지 눌러줍시다.

 

 

 그다음은 AndroidManifest.xml 파일을 켜줍니다.

 

하단 코드를 입력해서 인터넷 권한을 선언해줍니다.

 

<uses-permission android:name="android.permission.INTERNET"/>

 

그리고 안드로이드 9.0 이상부터는 application 태그 아래에 해당 조건도 true로 설정해줘야

에러가 일어나지 않습니다.

 

android:usesCleartextTraffic="true"

 

 

 

호스트pc와 Virtualbox 가상머신 네트워크 연결

이제 가상 머신에 네트워크 설정을 해주겠습니다.

 

설정을 누르고 네트워크 탭에 들어가 어댑터에 브리지를 선택해줍니다.

이름은 Intel(R) Wireless-AC 9461 을 선택해줍니다.

 

 

터미널을 열고 ifconfig 명령어를 실행해보면 eth0의 inet이 192.168.219.103으로 설정된 것을 볼 수 있습니다.

 

호스트 pc에서 해당 ip로 ping을 날려보니 잘 반응합니다. 연결이 잘되었네요

 

 

다시 가상머신으로 와서 /var/www/html/ 폴더에 login.php 파일을 하나 생성해줍니다.

hello 라는 글자를 출력해주는 php 코드입니다.

 

그리고 apache2와 mysql을 실행시켜줍니다.

 

 

호스트 pc에서 해당 ip로 login.php를 불러보겠습니다.

 

hello 라는 글자가 잘 출력됩니다!

 

 

 

DB 생성

이제 네트워크도 연결 되었으니 본격적으로 데이터베이스를 생성해보겠습니다.

 

mysql -u root -p 명령어를 통해 mysql을 실행시켜주고

CREATE DATABASE user; 를 통해 user라는 DB를 생성해줍니다.

 

 

그리고 아래 명령어를 입력해줍니다.

mysql> USE user;
mysql> CREATE table user (
    -> userID varchar(20) not null,
    -> userPassword varchar(20) not null,
    -> userName varchar(20) not null,
    -> userAge int not null,
    -> primary key(userID));

 

desc user; 명령어를 통해 확인해보니 테이블이 잘 생성된 것을 확인할 수 있습니다.

 

 

MySQL root 계정 비밀번호 설정

이 MySQL을 아까 설치한 phpmyadmin에서 접속하기 위해서는 root 계정의 비밀번호를 설정해야합니다.

현재 phpmyadmin 계정만 비밀번호가 있고 root 계정은 비밀번호가 invalid 상태입니다.

 

다음 명령어를 입력하면 볼 수 있습니다.

use mysql
show tables like 'user';
SELECT host, user, password from user;

처음에 

mariadb에서 사용한다는 비밀번호 변경 명령어를 입력했는데 에러가 났습니다.

UPDATE user set password=password('새 비밀번호') WHERE user='root';

 

알아보니 버전이 향상되면서 명령어가 변경되었던 것이었습니다.

 

아래 명령어를 입력하면 비밀번호를 변경할 수 있습니다.

SET password for 'root'@'localhost' = password('새 비밀번호');
FLUSH privileges;

 

확인하니 잘 변경된 것이 보입니다.

 

phpmyadmin을 켜서 해당 비밀번호를 root 아이디와 입력하면 로그인이 됩니다.

 

차후에 검증을 위해 hacker라는 계정 하나를 생성해두겠습니다.

 

테이블을 확인해보니 잘 추가되었습니다.

 

php와 mysql 연결

mysql에 접속할 수 있는 php 코드를 작성해보겠습니다.

 

웹 개발과 달리 php가 직접 페이지를 이동시키는 것이 아니므로 header 함수가 없고

db와 연결만 해줍니다. 액티비티가 POST로 전송한 값만 받아서 DB와 연결해 값을 꺼내옵니다.

 

login.php

<?php
session_start();

$host = 'localhost';
$dbusername = 'root';
$dbpassword = '비밀번호';
$dbname = 'user';

$con = mysqli_connect($host,$dbusername,$dbpassword,$dbname);
$userId = $_POST['id'];
$userpass = $_POST['pass'];

$prepare_query = $con -> prepare("SELECT userPW, userID FROM user WHERE userID=? AND userPW=?");
$prepare_query->bind_param("ss",$_POST["id"],$_POST["pass"]);
$prepare_query->execute();
$result = $prepare_query ->get_result();

if($result->num_rows==0){
   echo "invalid user";
} else {
   echo "success";
}
?>

해당 코드는 식별과 인증이 동시에 진행되는 로그인 방식입니다.

그러나 쿼리문이 string이 아니라 preparedstatement로 짜여져 있기 때문에

SQL Injection에 대한 방지가 됩니다.

조건문에 해당하는 행이 존재하면 success라는 글자를 출력하고

존재하지 않으면 invalid user라는 글자를 출력하게 되는데,

이 값이 밑에 서술할 kotlin 파일에 response로 전송됩니다.

(아마 따로 JSON 데이터값을 만들지 않으면 php 측에서 echo로 뱉은 String값이 전달되는 것 같습니다.)

 

Kotllin과 PHP 연결

(처음에 로그인 화면의 클래스 이름이 MainActivity.kt 였는데 헷갈릴 것 같아 LoginActivity.kt로 변경했습니다!)

 

LoginActivity.kt

class LoginActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)
        var context = this@LoginActivity

        val tvid: TextInputEditText = findViewById(R.id.textinputedittext_id)
        val tvpass: TextInputEditText = findViewById(R.id.textinputedittext_pass)
        // 로그인 버튼
        val btn_login: Button = findViewById(R.id.button_login)
        // 회원가입 버튼
        val tx_register: TextView = findViewById(R.id.tx_register)

        //1. 값을 가져온다
        //2. 클릭을 감지한다
        //3. 1번의 값을 다음 액티비티로 넘긴다

        // 회원가입 클래스로 이동 버튼
        tx_register.setOnClickListener(){
            val intent2 = Intent(this, Register::class.java)
            startActivity(intent2)
        }

        // 버튼이 클릭되면 다음 값 전송
        // 로그인 버튼
        btn_login.setOnClickListener() {
            // URL 주의하기 , 장소바뀔 때마다 ipconfig로 확인
            val url: String = "http://가상 머신 IP/apphtml/login.php"
            // trim을 사용하면 공백이 제거됨
            // 여기서 /**/를 이용하면 sql injection이 통할 수도 있음 주의
            val id = tvid.text.toString().trim()
            val pass = tvpass.text.toString().trim()
            //입력한 아이디와 비밀번호를 loginVolley에 담아서 해당 url에 전송
            // 그럼 php가 mysql db에서 데이터를 꺼내와서 kt 파일에 전송
            // 그 후 Intent로 다음 액티비티로 넘김
            loginVolley(this, url, id, pass)
        }
    }

    // Volley를 사용한 http 통신으로 로그인 하는 함수
    private fun loginVolley(context: Context, url: String, id: String, pass: String){
        // 1. RequestQueue 생성 및 초기화
        val requestQueue = Volley.newRequestQueue(context)

        // 2. Request Object인 StringRequest 생성
        val request: StringRequest = object : StringRequest(Method.POST, url,
        Response.Listener {
            // Intent to Dashboard Activity
            response ->
            if(response.trim().equals("success")){
                Toast.makeText(this,"로그인에 성공했습니다!",Toast.LENGTH_LONG).show()
            } else {
                Toast.makeText(this, "Check Your ID or password",Toast.LENGTH_LONG).show()
            }
        },
            Response.ErrorListener {
               error ->
               Toast.makeText(context, error.toString(), Toast.LENGTH_LONG).show()
            }) {
               // request 시 key, value 보낼 때
               // loginVolley에 있던 id, pass를 id, pass 라는 key를 씌워서 전송
               // JSON으로 가져온 데이터에다 MAP 함수를 이용하면 list로 바꿀 수 있다.
               override fun getParams(): MutableMap<String, String>? {
                   val params = HashMap<String, String>()
                   // params.put ("key", value)
                   // php에서 params.put("id", id)는 $_POST["id"] = id로 받는다.
                   params.put("id", id)
                   params.put("pass", pass)
                   return params
                   }
               }
        // 3. 생성한 StringRequest를 RequestQueue에 추가
        requestQueue.add(request)
    }
}

해당 코틀린 코드는 포스팅 초반에 설치했던 Volley 라이브러리를 이용해 PHP와 웹 통신을 합니다.

Intent 기능은 아직 넣지 않고 php와 통신해서 toast 메시지를 뱉어냅니다.

아이디와 비밀번호가 맞다면 로그인이 성공했다는 toast 메시지가 뜨고

맞지 않다면 id와 password를 Check하라는 toast 메시지가 뜹니다.

해당 경우가 아닌 외부적인 문제가 있다면 조건문에 의해 해당 error 를 toast 메시지로 뱉어냅니다.

 

사용자의 입력값은 textinputedittext 로 받습니다.

아이디는 변수 id, 비밀번호는 변수 pass로 받습니다.

toString() 으로 string으로 형변환하고 trim()으로 공백을 제거합니다.

이 함수는 sql injection에 대한 대비가 될 수 있지만

특수문자를 통한 공백을 사용하면 또다른 우회가 될 수 있어 아직 수정이 요구되는 코드입니다.

 

Intent 기능은 loginVolley 함수내부에 짜여질 예정입니다.

loginVolley 함수는 volley의 통신 라이브러리 예제를 많이 참조했습니다.

requestqueue 를 생성 및 초기화하고

requestobject인 stringobject를 생성한 후

생성한 stringrequeset를 requestqueue에 추가합니다.

전송하고자 하는 값은 getParams 내부에 key 와 value를 씌워 전송합니다.

 

 

앱 실행

앱을 실행하기 위해서는 가상머신의 apache2와 mysql을 실행시켜야 합니다.

 

그 후, 호스트 pc에서 run을 눌러 다 짜여진 코드를 ADB에 설치합니다.

 

설치가 완료되었습니다.

 

실행 후, 아이디와 비밀번호를 입력해보겠습니다.

포스팅 초반에 DB에 만들어놓았던 아이디와 비밀번호가 hacker인 계정으로 로그인해보겠습니다.

 

 

 

아이디와 비밀번호를 입력해보니 로그인이 성공했다는 toast 메시지가 뜹니다.

 

다음으로 db와 다르게 비밀번호를 살짝 틀려보았더니,

id와 password를 Check 하라는 toast 메시지가 뜹니다.

 

 

error를 테스트해보기 위해 칼리리눅스에서 mysql을 멈춰보겠습니다.

아이디와 비밀번호를 제대로 입력했는데도 php에서 mysql 값을 가져오지 못해

servererror를 출력하는 모습입니다.

입력한 모든 조건문이 제대로 동작하는 것이 확인되었습니다.

이제 Intent 기능을 추가해서 아이디와 비밀번호가 맞다면 메인 액티비티로 넘어가는 기능을 추가해서

다음 포스팅에서 구현해보겠습니다.

 

각오는 했었지만 kotlin과 php, mysql 연동이 낯설어서 그런지 정말 오래걸리고 장문의 포스팅이 되었네요

특히나 kotlin으로 로그인하는 예제는 framework를 사용하지 않은 레퍼런스를 찾기가 힘들고 환경셋팅도 조금씩 달라

알맞은 정보를 골라내기가 힘들었습니다.

java로 로그인하는 참조할만한 다른 글들은 굉장히 많았는데 의외로 kotlin은 정말 없더라구요

java로 구현할 걸 하는 후회도 들었지만 외국 유튜브까지 찾아가면서...고생한 끝에 결국 성공했습니다. 

 

봐주셔서 감사합니다!

 


 

소스 참조

어댑터에 브리지 선택 시 이름 없는 오류 해결법 : https://lifegoesonme.tistory.com/372

Kotlin과 php 연동 코드 참조 : https://link2me.tistory.com/1824

kotlin과 php 연동 코드 참조2 : https://github.com/jayfirke/Login-With-Kotlin-and-Php-MySQL/blob/master/MainActivity(Login).kt 

kotlin volley 사용 기본 예제 : https://altongmon.tistory.com/661

kotlin jsonobject의 민감성 : https://www.bsidesoft.com/7782

kotlin volley 사용 로그인 예제 유튜브 : https://www.youtube.com/watch?v=v2fIzl6v9vA