Creando nuestro sistema de registro y login en Android (II)

La semana pasada empezamos creando los formularios de login y registro en Android para nuestro sistema de autenticación y esta nos pasamos a la parte servidor. Como de costumbre nosotros lo haremos sobre PHP, pero vosotros podéis hacerlo sobre el lenguaje de servidor que mejor se os dé, Java, .NET...




Esta parte constará de 4 archivos, el primero de ellos será el de la configuración, config.php. Aquí debéis poner vuestra configuración para poder conectaros a la base de datos donde guardéis la info de los usuarios.


<?php

define("DB_HOST", "localhost");
define("DB_USER", "usr_nombre_usuario_bd");
define("DB_PASSWORD", "password_usr_nombre_usuario_bd");
define("DB_DATABASE", "db_nombre_base_de_datos");
?>

El siguiente de los archivos se llamará DB_Connect.php y simplemente es el encargado de conectar a la base de datos.


<?php
 
class DB_Connect {

    function __construct() {
 
    }

    function __destruct() {
        $this->close();
    }

    public function connect() {
        require_once 'config.php';
        $con = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD);
        mysql_select_db(DB_DATABASE);
 
        return $con;
    }
 
    public function close() {
        mysql_close();
    }
 
}
 
?>

El tercero de los archivos se llamará DB_Functions.php y en el se harán las conexiones a la base de datos.


<?php
 
class DB_Functions {
 
    private $db;
 

    function __construct() {
        require_once 'DB_Connect.php';       
        $this->db = new DB_Connect();
        $this->db->connect();
    }
 
    function __destruct() {
 
    }
 
    /**
     * Guardamos nuevos usuarios
     * Devolvemos detalle del usuario
     */
    public function storeUser($name, $email, $password) {
        $uuid = uniqid('', true);
        $hash = $this->hashSSHA($password);
        $encrypted_password = $hash["encrypted"]; // password encriptada
        $salt = $hash["salt"]; // salt
        $result = mysql_query("INSERT INTO users(unique_id, name, email, encrypted_password, salt, created_at) VALUES('$uuid', '$name', '$email', '$encrypted_password', '$salt', NOW())");
        // comprobamos que la query se ejecutó correctamente
        if ($result) {
            // obtener detalle del usuario
            $uid = mysql_insert_id(); 
            $result = mysql_query("SELECT * FROM users WHERE uid = $uid");
            // devolvemos detalle del usuario
            return mysql_fetch_array($result);
        } else {
            return false;
        }
    }
 
    /**
     * Obtenemos usuario por email y contraseña
     */
    public function getUserByEmailAndPassword($email, $password) {
        $result = mysql_query("SELECT * FROM users WHERE email = '$email'") or die(mysql_error());
        // verificamos el resultado de la query
        $no_of_rows = mysql_num_rows($result);
        if ($no_of_rows > 0) {
            $result = mysql_fetch_array($result);
            $salt = $result['salt'];
            $encrypted_password = $result['encrypted_password'];
            $hash = $this->checkhashSSHA($salt, $password);
            
            if ($encrypted_password == $hash) {
                // Se ha autenticado al usuario correctamente
                return $result;
            }
        } else {
            // usuario no encontrado
            return false;
        }
    }
 
    /**
     * Comprobamos si el usuario existe o no
     */
    public function isUserExisted($email) {
        $result = mysql_query("SELECT email from users WHERE email = '$email'");
        $no_of_rows = mysql_num_rows($result);
        if ($no_of_rows > 0) {
            // usuario existe
            return true;
        } else {
            // usuario no existe
            return false;
        }
    }
 
    /**
     * Encriptamos la password
     * devolvemos el salt y la password encriptada
     */
    public function hashSSHA($password) {
 
        $salt = sha1(rand());
        $salt = substr($salt, 0, 10);
        $encrypted = base64_encode(sha1($password . $salt, true) . $salt);
        $hash = array("salt" => $salt, "encrypted" => $encrypted);
        return $hash;
    }
 
    /**
     * Desencriptamos la password
     * Devolvemos una hash string
     */
    public function checkhashSSHA($salt, $password) {
 
        $hash = base64_encode(sha1($password . $salt, true) . $salt);
 
        return $hash;
    }
 
}
 
?>

En este se ha creado una función para insertar el usuario que al crearlo devuelve un array con los nuevos datos, también se puede buscar por email y contraseña o comprobar si el usuario ya existe.

El cuarto de los archivos se llamará index.php, a este es al que llegarán todas las peticiones de login y registro.


<?php
  /**
 * Comprobamos la petición POST
 */
if (isset($_POST['tag']) && $_POST['tag'] != '') {
    // obtenemos tag
    $tag = $_POST['tag'];
 
    require_once 'DB_Functions.php';
    $db = new DB_Functions();
 
    // Empezamos a preparar la respuesta en forma de Array que luego convertiremos en un json
    $response = array("tag" => $tag, "success" => 0, "error" => 0);
 
    // evaluamos tag
    if ($tag == 'login') {
        // chequeamos el login
        $email = $_POST['email'];
        $password = $_POST['password'];
 
        // obtenemos y comprobamos el usuario por email y password
        $user = $db->getUserByEmailAndPassword($email, $password);
        if ($user != false) {
            // usuario encontrado
            // marcamos el json como correcto con success = 1
            $response["success"] = 1;
            $response["uid"] = $user["unique_id"];
            $response["user"]["name"] = $user["name"];
            $response["user"]["email"] = $user["email"];
            $response["user"]["created_at"] = $user["created_at"];
            $response["user"]["updated_at"] = $user["updated_at"];
            echo json_encode($response);
        } else {
            // usuario no encontrado
            // marcamos el json con error = 1
            $response["error"] = 1;
            $response["error_msg"] = "Email o password incorrecto!";
            echo json_encode($response);
        }
    } else if ($tag == 'register') {
        // Registrar nuevo usuario
        $name = $_POST['name'];
        $email = $_POST['email'];
        $password = $_POST['password'];
 
        // comprobamos si ya existe el usuario
        if ($db->isUserExisted($email)) {
            // usuario ya existe - marcamos error 2
            $response["error"] = 2;
            $response["error_msg"] = "Usuario ya existe";
            echo json_encode($response);
        } else {
            // guardamos el nuevo usuario
            $user = $db->storeUser($name, $email, $password);
            if ($user) {
                // usuario guardado correctamente
                $response["success"] = 1;
                $response["uid"] = $user["unique_id"];
                $response["user"]["name"] = $user["name"];
                $response["user"]["email"] = $user["email"];
                $response["user"]["created_at"] = $user["created_at"];
                $response["user"]["updated_at"] = $user["updated_at"];
                echo json_encode($response);
            } else {
                // fallo en la inserción del usuario
                $response["error"] = 1;
                $response["error_msg"] = "Ocurrió un error durante el registro";
                echo json_encode($response);
            }
        }
    } else {
        echo "Petición no válida";
    }
} else {
    echo "Acceso denegado";
}
?>

Para comprobar la acción que vamos a realizar se enviará desde la app Android un parametro tag. Los valores serán login o register. En el login se buscará al usuario y si todo va bien se enviará un json con los datos del usuario. En caso contrario se envía un json con el motivo del error y un código de error.

El caso del registro es parecido, se registra al usuario y se crea un json con sus datos que devolveremos. En el caso de no enviar el tag o que no corresponda con algo esperado devolvemos texto plano ya que estas peticiones vendrán desde fuera de nuestra app Android y no conviene dar pistas sobre lo que se necesita para loguear un usuario.

Por último queda crear la tabla de base de datos donde almacenaremos a nuestros usuarios.


CREATE TABLE IF NOT EXISTS `users` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `unique_id` varchar(23) NOT NULL,
  `name` varchar(50) NOT NULL,
  `email` varchar(100) NOT NULL,
  `encrypted_password` varchar(80) NOT NULL,
  `salt` varchar(10) NOT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`uid`),
  UNIQUE KEY `unique_id` (`unique_id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Es una tabla muy simple donde guardaremos el nombre, email y contraseña encriptada del usuario, también datos como la fecha de creación, última actualización.

Por último, os recuerdo que este ejercicio es muy simple y que debéis extremar las medidas de seguridad a la hora de almacenar datos de usuarios. Nunca guardar su password sin encriptar, el servidor es recomendable que utilice una conexión https. Verificar las consultas en busca de vulnerabilidades como SQL inyection.

Hasta aquí llega la parte de servidor, como veis esta parte no es muy larga ni difícil, ya que se trata de unas pocas operaciones que nos ayudarán en la tarea de autenticar a los usuarios contra la base de datos de vuestro servidor.

Comments are closed.