Android với xác thực SMS tương tự ứng dụng WhatsApp - Phần 1

Đã có rất nhiều hướng dẫn phát triển hệ thống cho phép người dùng đăng nhập/đăng ký bằng cách thu thập tên người dùng, email và mật khẩu. Nhưng nếu bạn muốn đăng ký một người dùng sử dụng số điện thoại di động của họ như WhatsApp, Viber bằng cách kiểm tra số điện thoại di động của họ để có được người dùng chính xác thì đây chính là hướng dẫn dành cho bạn.

Trước khi tiếp tục tôi cần đảm bảo rằng bạn đã có kiến thức cơ bản về giao tiếp Android theo hình thức Client-Server. Nếu bạn là người mới, đừng lo lắng, những bài viết này (MySQL Spinner & PHP, MySQL - Android) sẽ cung cấp cho bạn một khởi đầu tốt.

Theo bài báo này có vẻ dài dòng, tôi đã chia nó thành hai phần. Trong phần này chúng ta sẽ tìm hiểu các phần phía máy chủ tức là xây dựng PHP, MySQL dự án bằng cách tích hợp các cổng tin nhắn SMS. Trong phần 2 chúng ta sẽ thực hiện việc tạo ứng dụng Android.

VIDEO DEMO

1. Làm thế nào để chúng hoạt động

Dưới đây là sơ đồ kiến trúc đơn giản để mô tả cách hoàn tất quá trình đăng ký mà liên quan đến PHP, MySQL server và một cổng SMS.

overview

  1. Đầu tiên sử dụng số điện thoại di động sẽ được gửi đến máy chủ của chúng ta, nơi row mới sẽ được tạo ra.

  2. Máy chủ của chúng ta yêu cầu các cổng SMS cho một sms đến số điện thoại di động với một mã xác minh.

  3. SMS Gateway sẽ gửi một tin nhắn SMS đến điện thoại người dùng với mã xác minh.

  4. Mã xác nhận sẽ được gửi trở lại máy chủ của chúng ta một lần nữa để xác minh. máy chủ của chúng ta kiểm tra nó và kích hoạt người sử dụng.

2. Lựa chọn SMS Gateway

SMS gateway là thực sự cần thiết trong việc gửi một tin nhắn SMS đến bất kỳ số điện thoại di động của bất kỳ nhà mạng di động. Về cơ bản các cổng có một hợp đồng với tất cả các mạng di động để gửi các tin nhắn SMS đến một số điện thoại di động cụ thể. Trong Ấn Độ, chúng tôi có rất nhiều nhà cung cấp tin nhắn SMS, nhưng việc lựa chọn các nhà cung cấp dịch vụ tin nhắn SMS tốt nhất là khó khăn. Tôi tìm thấy Solutions Infini, SMS Gupshup, Value First and Msg91 là khá phổ biến. Nhưng điều quan trọng nhất cần lưu ý khi lựa chọn các nhà cung cấp là đảm bảo rằng họ không hỗ trợ API REST như máy chủ của chúng ta cần phải kích hoạt SMS bất cứ khi nào có một yêu cầu đến từ các ứng dụng Android.

Tiếc là không có SMS gateway miễn phí để thử nghiệm ứng dụng Android của bạn. Bạn phải liên hệ với bất kỳ của các nhà cung cấp dịch vụ tìm kiếm một tài khoản demo hoặc mua khoản tín dụng dành cho tin nhắn SMS.

3. Việc đăng ký với MSG91 (API Key)

Để minh chứng cho hướng dẫn này, tôi đã chọn Msg91 cửa ngõ cho sự đơn giản của họ. Thực hiện theo các bước dưới đây để đăng ký và có được API Key REST của bạn. Xin lưu ý rằng cổng này chỉ dành cho người dùng Ấn Độ. Nếu bạn không phải là từ Ấn Độ, chọn cổng mà có sẵn trong đất nước của bạn.

  1. Đăng ký với Msg91.

  2. Mua các khoản tín dụng SMS bằng cách lựa chọn các thông tin thích hợp. Trong form hãy chọn SMS Type như TRANSACTIONAL ROUTE và cho số lượng SMS 2500 đó là các khoản chi phí tối thiểu để mua. Các chi phí sẽ vào khoảng 600 ₹.

  3. Tiến hành thanh toán. Khi thanh toán đã được thực hiện, bạn có thể xem các khoản tín dụng SMS ghi có vào tài khoản của bạn.

  4. Để có API key của bạn, truy cập API doc và nhấp chuột vào KEY ở góc trên bên phải. Bạn sẽ được hiển thị API Key của bạn trong một hộp thoại popup. Sao chép API Key này, chúng ta sẽ cần nó trong dự án PHP của chúng ta.

Kiểm tra lại một lần các bước đăng ký theo video dưới đây:

https://youtu.be/026wzlW1uF4

4. Xây dựng PHP, MySQL REST API

Bây giờ chúng ta có API KEY cần thiết để gửi các tin nhắn SMS. Hãy bắt đầu xây dựng PHP project cần thiết cho ứng dụng Android. Chúng tôi sẽ xây dựng một REST API đơn giản để quản lý những người dùng đăng ký bằng cách sử dụng các ứng dụng Android. Và kết thúc project này, chúng ta nên xây dựng hai end point cần thiết để người dùng có thể đăng ký. Một để người dùng đăng ký trong đó sẽ có gửi một SMS với mã xác nhận. Endpoint thứ hai để xác nhận code và hoàn thành quá trình đăng ký người dùng

4.1 Cài đặt phần mềm WAMP

Download và cài đặt WAMP server từ http://www.wampserver.com/en/. Một khi được cài đặt WAMP, khởi động chương trình từ Start ⇒ All Programs ⇒ ⇒ WampServer StartWampServer. Nếu bạn đang ở trên máy Mac, MAMP sẽ hữu ích.

Bạn có thể kiểm tra máy chủ của bạn bằng cách mở địa chỉ http://localhost/ trong trình duyệt của bạn. Ngoài ra bạn có thể kiểm tra bằng cách mở phpmyadmin http://localhost/phpmyadmin

4.2 Tạo cơ sở dữ liệu MySQL

Đối với dự án này, chúng tôi cần hai bảng. Một là bảng users để lưu trữ các thông tin người dùng và thứ hai là sms_codes để lưu trữ mã xác minh sms của người dùng.

Dưới đây là những cột cần thiết trong mỗi bảng. table

Mở http: http://localhost/phpmyadmin và thực hiện các truy vấn dưới đây để tạo ra cơ sở dữ liệu và bảng cần thiết.

Create a database named android_sms.

CREATE DATABASE android_sms;

USE android_sms;

Tạo bảng được yêu cầu và mối quan hệ bằng cách thực hiện dưới đây truy vấn sql.

CREATE TABLE `sms_codes` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `code` varchar(6) NOT NULL,
  `status` int(1) NOT NULL DEFAULT '0',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `email` varchar(250) NOT NULL,
  `mobile` varchar(10) NOT NULL,
  `apikey` varchar(32) NOT NULL,
  `status` int(1) NOT NULL DEFAULT '0',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=64 ;

ALTER TABLE `sms_codes`
  ADD CONSTRAINT `sms_codes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

4.3 Tạo PHP Project

Một khi bạn đang thực hiện với thiết lập cơ sở dữ liệu, hãy di chuyển để phát triển dự án php. Bạn có thể sử dụng bất kỳ IDE như Netbeans để phát triển dự án này hoặc chỉ cần notepad ++ là đủ.

  1. Goto WAMP thư mục dự án tức là C:/wamp/www và tạo ra một thư mục có tên android_sms. Đây sẽ là thư mục gốc của dự án PHP của chúng ta.

  2. android_sms Bên trong, tạo ra một thư mục có tên include. Trong thư mục này, chúng tôi giữ tất cả các thông tin cấu hình cơ sở dữ liệu, Msg91 API Key, vv,

  3. Tạo một tập tin dưới bao gồm các thư mục có tên config.php và thêm mã dưới đây. Thay thế các thông tin MySQL và Msg91 API Key trong code dưới đây với các thông tin bạn có bạn.

Config.php
<?php
/**
 * Database configuration
 */
define('DB_USERNAME', 'root');
define('DB_PASSWORD', 'root');
define('DB_HOST', 'localhost');
define('DB_NAME', 'android_sms');

/**
 * MSG91 configuration
 */
define('MSG91_AUTH_KEY', "88276AGwzewOEdFs559d2888");
// sender id should 6 character long
define('MSG91_SENDER_ID', 'ANHIVE');

define('USER_CREATED_SUCCESSFULLY', 0);
define('USER_CREATE_FAILED', 1);
define('USER_ALREADY_EXISTED', 2);
?>
  1. Trong thư mục include, tạo ra một tập tin php tên DbConnect.php tập tin này thực hiện các kết nối cơ sở dữ liệu.
DbConnect.php
<?php

/**
 * Handling database connection
 *
 * @author Ravi Tamada
 * @link URL Tutorial link
 */
class DbConnect {

    private $conn;

    function __construct() {
    }

    /**
     * Establishing database connection
     * @return database connection handler
     */
    function connect() {
        include_once dirname(__FILE__) . '/Config.php';

        // Connecting to mysql database
        $this->conn = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);

        // Check for database connection error
        if (mysqli_connect_errno()) {
            echo "Failed to connect to MySQL: " . mysqli_connect_error();
            exit;
        }

        // returing connection resource
        return $this->conn;
    }

}

?>
  1. Tạo một file php tên DbHandler.php trong thư mục include. Tập tin này có chứa các chức năng chính để thực hiện việc đọc, ghi các bản ghi trên cơ sở dữ liệu.
DbHandler.php
<?php

/**
 * Class to handle all db operations
 * This class will have CRUD methods for database tables
 *
 * @author Ravi Tamada
 * @link URL Tutorial link
 */
class DbHandler {

    private $conn;

    function __construct() {
        require_once dirname(__FILE__) . '/DbConnect.php';
        // opening db connection
        $db = new DbConnect();
        $this->conn = $db->connect();
    }

    /* ------------- `users` table method ------------------ */

    /**
     * Creating new user
     * @param String $name User full name
     * @param String $email User login email id
     * @param String $mobile User mobile number
     * @param String $otp user verificaiton code
     */
    public function createUser($name, $email, $mobile, $otp) {
        $response = array();

        // First check if user already existed in db
        if (!$this->isUserExists($mobile)) {

            // Generating API key
            $api_key = $this->generateApiKey();

            // insert query
            $stmt = $this->conn->prepare("INSERT INTO users(name, email, mobile, apikey, status) values(?, ?, ?, ?, 0)");
            $stmt->bind_param("ssss", $name, $email, $mobile, $api_key);

            $result = $stmt->execute();

            $new_user_id = $stmt->insert_id;

            $stmt->close();

            // Check for successful insertion
            if ($result) {

                $otp_result = $this->createOtp($new_user_id, $otp);

                // User successfully inserted
                return USER_CREATED_SUCCESSFULLY;
            } else {
                // Failed to create user
                return USER_CREATE_FAILED;
            }
        } else {
            // User with same email already existed in the db
            return USER_ALREADY_EXISTED;
        }

        return $response;
    }

    public function createOtp($user_id, $otp) {

        // delete the old otp if exists
        $stmt = $this->conn->prepare("DELETE FROM sms_codes where user_id = ?");
        $stmt->bind_param("i", $user_id);
        $stmt->execute();

        $stmt = $this->conn->prepare("INSERT INTO sms_codes(user_id, code, status) values(?, ?, 0)");
        $stmt->bind_param("is", $user_id, $otp);

        $result = $stmt->execute();

        $stmt->close();

        return $result;
    }

    /**
     * Checking for duplicate user by mobile number
     * @param String $email email to check in db
     * @return boolean
     */
    private function isUserExists($mobile) {
        $stmt = $this->conn->prepare("SELECT id from users WHERE mobile = ? and status = 1");
        $stmt->bind_param("s", $mobile);
        $stmt->execute();
        $stmt->store_result();
        $num_rows = $stmt->num_rows;
        $stmt->close();
        return $num_rows > 0;
    }

    public function activateUser($otp) {
        $stmt = $this->conn->prepare("SELECT u.id, u.name, u.email, u.mobile, u.apikey, u.status, u.created_at FROM users u, sms_codes WHERE sms_codes.code = ? AND sms_codes.user_id = u.id");
        $stmt->bind_param("s", $otp);

        if ($stmt->execute()) {
            // $user = $stmt->get_result()->fetch_assoc();
            $stmt->bind_result($id, $name, $email, $mobile, $apikey, $status, $created_at);

            $stmt->store_result();

            if ($stmt->num_rows > 0) {

                $stmt->fetch();

                // activate the user
                $this->activateUserStatus($id);

                $user = array();
                $user["name"] = $name;
                $user["email"] = $email;
                $user["mobile"] = $mobile;
                $user["apikey"] = $apikey;
                $user["status"] = $status;
                $user["created_at"] = $created_at;

                $stmt->close();

                return $user;
            } else {
                return NULL;
            }
        } else {
            return NULL;
        }

        return $result;
    }

    public function activateUserStatus($user_id){
        $stmt = $this->conn->prepare("UPDATE users set status = 1 where id = ?");
        $stmt->bind_param("i", $user_id);

        $stmt->execute();

        $stmt = $this->conn->prepare("UPDATE sms_codes set status = 1 where user_id = ?");
        $stmt->bind_param("i", $user_id);

        $stmt->execute();
    }

    /**
     * Generating random Unique MD5 String for user Api key
     */
    private function generateApiKey() {
        return md5(uniqid(rand(), true));
    }
}
?>
  1. Bây giờ chúng ta đã có phần core logic. Hãy tạo ra một endpoint để đăng ký người dùng. Trong thư mục gốc của dự án của bạn, tạo ra một tập tin có tên request_sms.php. Trong đoạn mã dưới đây
  • Đầu tiên chúng ta nhận được name, emailmobile number người dùng được gửi đi từ các thiết bị Android với phương thức POST.
  • Chúng ta tạo ra một bản ghi mới trong bảng users bằng cách gọi phương thức createUser(). Ban đầu, status của người dùng sẽ là 0 để chỉ người dùng đang inactive. Trạng thái này sẽ được đổi lại thành 1 khi người dùng xác thực OTP.
  • Khi bản ghi mới của người dùng được tạo, chúng ta yêu cầu một tin nhắn SMS đến các số điện thoại di động bằng cách gọi phương thức sendSms().
  • sendSms() sẽ thực hiện yêu cầu đến Msg91 REST API để gửi tin nhắn SMS với 6 chữ số OTP đến người dùng với số điện thoại di động đã cung cấp.

Dưới đây là mẫu tin nhắn SMS mà người dùng sẽ nhận được trên điện thoại di động của họ. Các OTP nên được bắt đầu bằng: và khoảng trắng trong tin nhắn.

Hello! Welcome to AndroidHive. Your OPT is : 228767

request_sms.php
<?php

include './include/DbHandler.php';
$db = new DbHandler();

$response = array();

if (isset($_POST['mobile']) && $_POST['mobile'] != '') {

    $name = $_POST['name'];
    $email = $_POST['email'];
    $mobile = $_POST['mobile'];

    $otp = rand(100000, 999999);

    $res = $db->createUser($name, $email, $mobile, $otp);

    if ($res == USER_CREATED_SUCCESSFULLY) {

        // send sms
        sendSms($mobile, $otp);

        $response["error"] = false;
        $response["message"] = "SMS request is initiated! You will be receiving it shortly.";
    } else if ($res == USER_CREATE_FAILED) {
        $response["error"] = true;
        $response["message"] = "Sorry! Error occurred in registration.";
    } else if ($res == USER_ALREADY_EXISTED) {
        $response["error"] = true;
        $response["message"] = "Mobile number already existed!";
    }
} else {
    $response["error"] = true;
    $response["message"] = "Sorry! mobile number is not valid or missing.";
}

echo json_encode($response);

function sendSms($mobile, $otp) {

    $otp_prefix = ':';

    //Your message to send, Add URL encoding here.
    $message = urlencode("Hello! Welcome to AndroidHive. Your OPT is '$otp_prefix $otp'");

    $response_type = 'json';

    //Define route
    $route = "4";

    //Prepare you post parameters
    $postData = array(
        'authkey' => MSG91_AUTH_KEY,
        'mobiles' => $mobile,
        'message' => $message,
        'sender' => MSG91_SENDER_ID,
        'route' => $route,
        'response' => $response_type
    );

//API URL
    $url = "https://control.msg91.com/sendhttp.php";

// init the resource
    $ch = curl_init();
    curl_setopt_array($ch, array(
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $postData
            //,CURLOPT_FOLLOWLOCATION => true
    ));

    //Ignore SSL certificate verification
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

    //get response
    $output = curl_exec($ch);

    //Print error if any
    if (curl_errno($ch)) {
        echo 'error:' . curl_error($ch);
    }

    curl_close($ch);
}
?>
  1. Bây giờ chúng ta cần phải tạo ra một endpoint để xác thực OTP. Tạo một tập tin php tên verify_otp.php với nội dung dưới đây.

Trong đoạn mã dưới đây

  • Các OTP sẽ được nhận từ các thiết bị Android qua một param POST.
  • Người dùng phù hợp với OTP được lấy từ bảng users.
  • Sau đó, status người dùng sẽ chuyển sang 1 trong cả hai bảng userssms_code để đánh dấu trạng thái người dùng đã được active.
  • Hai bước trên được thực hiện trong phương thức activateUser().
verify_otp.php
<?php

include './include/DbHandler.php';
$db = new DbHandler();

$response = array();
$response["error"] = false;

if (isset($_POST['otp']) && $_POST['otp'] != '') {
    $otp = $_POST['otp'];

    $user = $db->activateUser($otp);

    if ($user != NULL) {

        $response["message"] = "User created successfully!";
        $response["profile"] = $user;
    } else {
        $response["message"] = "Sorry! Failed to create your account.";
    }

} else {
    $response["message"] = "Sorry! OTP is missing.";
}

echo json_encode($response);
?>

5. Kiểm tra các API REST

Để kiểm tra API của chúng ta có thể sử dụng extension Postman

Request SMS

URL Method Parameters Description
http://localhost/android_sms/request_sms.php POST name, email, mobile Request SMS

Chuỗi json dưới đây sẽ được tạo ra khi tin nhắn SMS được gửi thành công.

{
    "error": false,
    "message": "SMS request is initiated! You will be receiving it shortly."
}

Xác thực OTP của người dùng

URL Method Parameters Description
http://localhost/android_sms/verify_otp.php POST otp verifying user verification code

Khi OTP được xác thực thành công, thông tin profile người dùng đầy đủ phải được xuất ra trong chuỗi JSON.

{
    "error": false,
    "message": "User created successfully!",
    "profile": {
        "name": "Ravi Tamada",
        "email": "[email protected]",
        "mobile": "0000000000",
        "apikey": "088d196bacbe6bf08657720c9d562390",
        "status": 0,
        "created_at": "2015-07-30 22:18:59"
    }
}

Xem video dưới đây biết làm thế nào để sử dụng Postman để kiểm tra các endpoint.

Nguồn tham khảo: Android adding SMS Verification Like WhatsApp – Part 1


All Rights Reserved