Objetivo

El objetivo de este post es compartir un experimento que estamos realizando en Charrúa para enviar datos con nuestro dispositivo IoT (Internet of Things) a una aplicación realizada con Laravel.

En primer lugar debes estar familiarizado con Laravel y el protocolo OAuth2 que será el utilizado para realizar las solicitudes de manera autenticada a nuestra API. El dispositivo que utilizaremos para este experimento será un Arduino MKR1000 y el entorno Arduino Web Editor.
Por si no conoces el entorno Arduino Web Editor, es lo que se utiliza con los nuevos modelos como el MKR1000 para programar y enviar el código al dispositivo mediante un ordenador.

El tipo de credencial que utilizaremos para enviar datos desde el dispositivo será Client Credentials Grant Token. Es un tipo de credencial que normalmente se utiliza para autenticar una máquina con otra máquina (machine-to-machine). En este caso una de las máquinas sera nuestro dispositivo MKR1000 y la otrá será nuestra API.

Comenzaremos por crear nuestra aplicación Laravel:

laravel new IOTAuth

Hemos escogido IOTAuth para el nombre de nuestra aplicación, esto lo dejamos a tu criterio. Si tienes problemas para instalar Laravel puedes consultar la documentación: https://laravel.com/docs/5.8/installation#installation

¿NECESITAS AYUDA CON TU WEB?

Si buscas mejorar tu página web o tienda online, estás en el lugar adecuado. Trabajemos juntos para impulsar tu presencia en línea y hacer realidad tus objetivos.

¡HABLEMOS DE TU PROYECTO!

Conecta la base de datos

Deberás ir al archivo .env en la raíz de tu aplicación y agregar las credenciales de tu base de datos. Recuerda sustituir los valores <nombre_bd>, <usuario_bd> y <contraseña_bd> por los que hayas creado.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=nombre_bd
DB_USERNAME=usuario_bd
DB_PASSWORD=contraseña_bd

Instalaremos el paquete de autenticación OAuth2 para API’s – Passport

Laravel Passport es un paquete utilizado para añadir fácilmente autenticación a nuestra API. Este paquete provee una implementación total de OAuth2.

Para realizar la instalación seguiremos los pasos de la documentación.

Utilizaremos composer para la instalación del paquete, con el comando:

composer require laravel/passport

Realizaremos la migración:

php artisan migrate

La migración generará las tablas necesarias para que nuestra aplicación Laravel quede operativa. Entre ellas creará las tablas de passport y la tabla de usuarios.

Generación de claves e instalación:

Tendrás que ejecutar un comando encargado de crear las llaves de encriptación necesarias para generar los tokens de acceso. Este comando también generará dos clientes uno del tipo personal access y otro del tipo password grant. Ignoraremos por el momento estas credenciales ya que ninguna nos interesa, recordemos la que queremos utilizar es para la comunicación de máquina a máquina (Client Credentials Grant Token).

php artisan passport:install

Generación del cliente para el tipo de credencial deseada: Client Credentials Grant Tokens

Antes de que nuestra aplicación pueda generar tokens, debemos generar el cliente. Pues bien, ahora debemos ejecutar el siguiente comando:

php artisan passport:client --client

Este comando nos preguntará el nombre para nuestro nuevo cliente, nosotros utilizamos mkr1000_01 y al confirmar el nombre, nos dará como resultado en la propia consola el ID del cliente y una clave secreta.

What should we name the client? [Access ClientCredentials Grant Client]:
 > mkr1000_01

New client created successfully.
Client ID: 3
Client secret: qV524tNf2ofA6VsQCaqyBAPVayXCj0i4nIup1b

Desde la documentación de Laravel (https://laravel.com/docs/5.8/passport#client-credentials-grant-tokens) nos dicen que para que esto funcione correctamente, debemos agregar el CheckClientCredentials middleware a $routeMiddleware en app/Http/Kernel.php.

use Laravel\Passport\Http\Middleware\CheckClientCredentials;

protected $routeMiddleware = [
    'client' => CheckClientCredentials::class,
];

Para proteger una ruta, agregaremos el middleware «client», lo verás en el siguiente punto.

Creación y protección de la ruta/s

Iremos a nuestro archivo api.php, es el encargado de gestionar y resolver las rutas de nuestra API. El archivo podemos encontrarlo en routes/api.php.

Vamos a crear nuestra ruta de prueba, agregamos al archivo api.php:

Route::middleware('client')->get('/protected-route', function (Request $request) {
    return "Este texto certifica que has ingresado correctamente";
}

Lo que sucederá aquí será que cuando intentemos ir a la URL http://127.0.0.1/api/protected-route el sistema nos obligue a estar autenticados y podamos ver la frase configurada «Este texto certifica que has ingresado correctamente».

Probar la API localmente

Para probar las rutas utilizaremos Postman, un software utilizado para interactuar con API’s.

Iniciar nuestro servidor con el comando:

php artisan serve

Podemos probar que nuestra aplicación funciona correctamente escribiendo en el navegador http://127.0.0.1:8080

Solicitar token de acceso:

Luego, debemos solicitarle a nuestra API un token de acceso, y de esta manera acceder a los recursos de manera autenticada. Para ello ejecutamos Postman, y vamos a configurar un nuevo request:

Tal como dice la documentación de passport, debemos agregar ciertos parámetros a nuestro request. El ejemplo a continuación es para solicitar el token con PHP, pero veremos que campos son necesarios para esta solicitud.

$guzzle = new GuzzleHttp\Client;

$response = $guzzle->post('http://127.0.0.1:8080/oauth/token', [
    'form_params' => [
        'grant_type' => 'client_credentials',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'scope' => '*',
    ],
]);

return json_decode((string) $response->getBody(), true)['access_token'];

Antes que nada, en Postman, haremos una prueba de nuestra URL protegida, simplemente haremos una solicitud GET a http://127.0.0.1:8080/api/protected-route y veremos que el resultado será un error de búsqueda de ruta (no nos esta mostrando la frase que esperábamos, vamos por buen camino)

En postman, configuraremos un POST request a la URL http://127.0.0.1:8080/oauth/token, adjuntando los parametros de formulario necesarios (grant_type, client_id, client_secret y scope).

Para nuestro ejemplo los valores serían:

'grant_type' => 'client_credentials',
'client_id' => '3',
'client_secret' => 'qV524tNf5ofA6VsQCaqyBAPVayXCj0y4nIup1b',
'scope' => '*',

El resultado de esta solicitud es una respuesta en JSON desde nuestra API con el token de acceso, el tipo de token y el tiempo de vida o validez.

postman-api-request-token

Un ejemplo de la respuesta podría ser:

{"token_type":"Bearer","expires_in":31622400,"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjVhOWIzZjk5MTk4NWViOTRmZTFkZDk5NTZiNmU1NjI4MjhlMTI5MTkyOTAxMGI5ZjdiYTBjNDQ1ODk2OTVkOGIwYTVjMjA5NTBhMDhiMTljIn0.eyJhdWQiOiIzIiwianRpIjoiNWEasd32324r32fqeaf5NGZlMWRkOTk1NmI2ZTU2MjgyOGUxMjkxOTI5MDEwYjlmN2JhMGM0NDU4OTY5NWQ4YjBhNWMyMDk1MGEwOGIxOWMiLCJpYXQiOjE1NTkzNzMzNTAsIm5iZiI6MTU1OTM3MzM1MCwiZXhwIjoxNTkwOTk1NzUwLCJzdWIiOiIiLCJzY29wZXMiOlsiKiJdfQ.erCdhJQP4pn-f28YA4mlZNUQca4B1JQTBO7T8AddqfkFJL_de-zFc_yyKnZoNioi6kqYiV8FkYg4QUtKT096d7ypB0UF_ii4ews15J95a_-asdasddG1tfw4F_98QaroKMH0YsPCma-KoR3St2Sz7Awu-tCLG_PGbpgGL_NsSCxeioFnwq8tKOASj7wTSnwaErUbSRQaf6MHGxLvqRrCsu_xoKHQyJHyYdt4Mwoh-z9d3ECKyEZjAQnPb9oCgZzHYFevtYq120llExdpxJqndtxt0CEh6y_tUBL3SlRwrsCOlcVBa83_YEiSL5PFonZ93X2o6fcTi__2VfhqJES2d1eh7YCBr8RfBxk_ll6HeFoafNZxqv9VZVLPmmcpcggg9dhKJtVXG7Tejib0mXMQFuUd3F065f29RYCGM6UuTyc4qgsrASUmLrHDH9QdlfItIqQGbjfI1U0I1_4CY9bUQll8asloqxpwtqSr6OP1q1s-P1Z65hGHWW79gPypnV1QFz31QTPhNG3db7R5XfE0v_dGNK_uPpqKsL3W5FC41cM6aBpeiOP8z1gyK697MTIHwXJTDDFvaXf65kOhbODKptDV6_1Wx2o1sKTWysqQbGMMGJnB2na613wCRd2ckL4pmrd6vwMdwyw0_Ds1ula5kl-QoQ9N8s1B7P0X1Jic"}

En este punto hemos hecho la solicitud mediante POST y tenemos en nuestro poder el token deseado para realizar la solicitud a nuestra ruta protegida.

Acceder a la ruta protegida:

Crearemos una nueva solicitud en Postman, esta vez una del tipo GET a la ruta protegida: http://127.0.0.1:8080/api/protected-route y agregaremos una cabecera (header) Autorization con el valor Bearer <aquí el token>.

Si has seguido todos los pasos anteriores, al ejecutar esta solicitud deberías ver la frase deseada «Este texto certifica que has ingresado correctamente».

postman-api-authenticated-access

Cargar código a nuestro dispositivo MKR1000

Para esta sección vamos a utilizar el Arduino MKR1000, la librería WiFi101 y subiremos el código mediante el Arduino Web Editor.

Arduino MKR1000 – https://store.arduino.cc/arduino-mkr1000
WiFi101 – https://www.arduino.cc/en/Reference/WiFi101
Arduino Web Editor – https://create.arduino.cc

Hemos modificado levemente el ejemplo de la librería llamado WiFiWebClient.ino:

#include <SPI.h>
#include <WiFi101.h>

char ssid[] = "myNetwork";          //  your network SSID (name) 
char pass[] = "myPassword";         // your network password
int keyIndex = 0;                   // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;

const char server[] = "example.com";              // name address for Google (using DNS)
const String api_route = "/api/protected-route";  // our api route

// get this from the api auth flow
const String access_token = "your-token-here";

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
WiFiClient client;

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to wifi");
  printWiFiStatus();

  Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.println("connected to server");
    // Make a HTTP request:
    client.println("GET " + api_route + " HTTP/1.1");
    client.println("Host: " + String(server));
    client.println("Authorization: Bearer " + access_token);
    client.println("Connection: close");
    client.println();
  }
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  while (client.available()) {
    char c = client.read();
    Serial.write(c);
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting from server.");
    client.stop();

    // do nothing forevermore:
    while (true);
  }
}


void printWiFiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Puedes ver el gist aquí: https://gist.github.com/danielcharrua/b022bef64e906acd5a897c5b2915d3fa

Deberás modificar algunas lineas para que esto te funcione correctamente:

Línea 4 y 5 – completa con el nombre y la contraseña de tu red WiFi.
Línea 10 – completa con el dominio de tu API.
Línea 11 – completa con la ruta protegida a la que queremos acceder.
Línea 14 – completa con el token de acceso previamente solicitado con Postman.

Probar API y Arduino MKR en producción

Llegados a este punto, llevaremos nuestra aplicación Laravel a un servidor público. Esto lo debemos hacer ya que el Arduino ejecutará un cliente web, imaginemos como un dispositivo que se conecta a internet y se comunicará con nuestra API.

Sube tu aplicación Laravel:

Sube los archivos a un servidor, para seguir el ejemplo supongamos que subes tu aplicación Laravel a example.com. Instala los paquetes de composer, conecta la base de datos, corre las migraciones, instala Passport, genera las claves y genera el cliente nuevo (el mismo proceso que has hecho localmente).

composer install
php artisan migrate
php artisan passport:install
php artisan passport:client --client

Si introduces la URL en tu navegador deberías ver la pantalla inicial de Laravel, eso es buena señal, significa que nuestra aplicación está funcionando correctamente.

Prueba la API con Postman:

Hagamos una breve prueba con Postman para asegurar que nuestra API está funcionando correctamente. Solicita un token como lo hemos hecho en el paso 5.b.

Una vez tengas el nuevo token de acceso, lo vamos a cargar en nuestro código para el Arduino MKR1000.

Prueba la comunicación desde el Arduino con la API:

Hemos llegado al último paso, subir el código al Arduino y ver el resultado por el puerto serial del mismo. Debemos ver entre las líneas de respuesta de nuestro request, la frase objetivo que introdujimos en la ruta protegida.

Attempting to connect to SSID: myNetwork
Connected to wifi
SSID: myNetwork
IP Address: 192.168.2.92
signal strength (RSSI):-82 dBm

Starting connection to server...
connected to server
HTTP/1.1 200 OK
Date: Wed, 05 Jun 2019 11:08:00 GMT
Content-Type: text/html; charset=UTF-8

52
Este texto certifica que has ingresado correctamente
0

disconnecting from server.

Conclusión

Hemos creado una comunicación desde un Arduino MKR1000 de manera inalámbrica (WiFi) y autenticada con nuestra API en una aplicación Laravel.

Con esto podríamos enviar datos de manera segura y autenticada desde sensores directamente a nuestra aplicación Laravel.

Posibles ideas para mejoras futuras:
– Realizar las solicitudes con el protocolo https:// en vez de con http://
– Realizar el proceso completo desde el Arduino (solicitar token y utilizar el mismo en los requests).

Si tienes comentarios o ideas, puedes comentarlos debajo del artículo.

HAGAMOS DESPEGAR TU NEGOCIO ONLINE 🚀

Te ayudo a potenciar tu página web o tienda online con estos servicios.

DESARROLLO WEB

MANTENIMIENTO WEB

CONSULTORÍA WEB

OPTIMIZACIÓN WPO

DESINFECCIONES

SOPORTE WEB

Publicaciones Similares

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Responsable: charrua.es. Finalidad: Poder contestar tu solicitud. Almacenamiento de los datos: Los datos son almacenados en un servidor alojado dentro de la UE y gestionado por charrua.es. Derechos: En cualquier momento puedes limitar, recuperar y borrar tu información.