Artículo
· 13 feb, 2023 Lectura de 6 min

Añadir validación Api-Key en peticiones REST

 

Hola! recientemente tuve que aplicar validación api-key a un desarrollo que teníamos hecho con un montón de endpoints y me he decidido a compartir con vosotros como lo llevé a cabo de una forma centralizada.

En este artículo os voy a explicar como podemos aplicar de una forma genérica (o no) validación api key a todos los endpoints de nuestra Web App.

Para el desarrollo utilicé la clase Base.cls de la plantilla iris-rest-api-template

La cual modifiqué un poco para que se adaptase a lo que necesitaba. La idea es que en vuestros desarrollos copiéis la clase Base.cls en vuestro proyecto y la uséis para extender vuestras propias implementaciones.

 

Lo primero que hice fue añadir un nuevo parámetro a la clase llamado ApiKey e inicializado a vacío:

Parameter ApiKey = "";

 

A continuación lo que hice fue modificar el metodo OnPreDispatch. Este metodo es ejecutado antes de procesar cualquier petición con lo cual me pareció el sitio perfecto para añadir una validación api key.

En el metodo añadí la llamada a un nuevo metodo que cree llamado ValidateApiKey

 

El metodo ValidateApiKey lo implementé asi:

ClassMethod ValidateApiKey(pUrl As %String, pMethod As %String, ByRef pContinue As %Boolean)  As %Status
{
  SET tSC = $$$OK
  QUIT:(..MustCheckApiKey(pUrl, pMethod)=0) tSC

  IF (..#ApiKey '= "")
    {
      IF ($D(%request.CgiEnvs("HTTP_API_KEY"))'=0)
      {

        SET apiKey=%request.CgiEnvs("HTTP_API_KEY")
        IF (apiKey'=..#ApiKey)
        {
          SET pContinue = 0
          DO ..ReportHttpStatusCode(..#HTTP401UNAUTHORIZED)
          SET tSC=$$$ERROR(..#HTTP401UNAUTHORIZED)
         
        }

      }
    }
  Quit tSC
}

 

En este metodo lo primero que hacemos es comprobar si debemos validar o no el apiKey para esta petición en el metodo MustCheckApiKey. (Podríamos tener una parte pública de nuestro api que no queremos proteger por apiKey)

Este método lo he creado para que podamos sobreescribirlo si no queremos que se aplique a todas las peticiones ya que por defecto siempre devuelve True

ClassMethod MustCheckApiKey(pUrl As %String, pMethod As %String) As %Boolean
{
  Quit 1
}

Como podéis comprobar recibe pUrl y pMethod:

pUrl contiene la dirección a la que se está haciendo la petición ej:

https://www.miApp.com/peticion1

 

pMethod contiene el verbo de la petición: GET, POST, PUT...

 

Con esta información podríamos hacer filtrados para indicar si queremos aplicar la validación apiKey o no.

 

Ejemplo: 

Sobreescribiendo el metodo MustCheckcApiKey en nuestra clase extendida podríamos decir que si la petición es un Get a la Home no aplique validación api Key

ClassMethod MustCheckApiKey(pUrl As %String, pMethod As %String) As %Boolean
{
  SET res = 1
  If (pUrl="/home")&(pMethod="GET")
  {
      Set res=0
  }

  Quit res
}

 

A continuación validamos si hemos establecido en nuestra clase un valor para el parámetro ApiKey y si es así entonces comprobamos que el valor de la propiedad "api-key" que vendrá en el header de la petición coincide con el valor de nuestro parámetro ApiKey.

 

(El valor se debe pasar en el header como "api-key" o "api_key" cualquiera de los dos serviría)

 

En caso afirmativo devolverá la información y en caso contrario devolverá un error "Unauthorized 401".

 

Os pongo un ejemplo de uso que he hecho sobre mi proyecto cos-url-shortener

Este proyecto es un ejemplo de como hacer un acortador de URL's con un docker IRIS. 

 

Para un caso como este, el endpoint de generación de URL's cortas quizás queramos protegerlo con un apiKey porque queremos que solo lo usen nuestros clientes pero cuando un usuario intente acceder a un link acortado no tendría sentido aplicarle una validación api-key.

 

¿Como se haría?

Primero nos aseguramos que nuestra clase extiende de la clase Base.cls

Class AQS.urlShortener.UrlREST Extends urlShortener.REST.Base

 

Después sobreescribimos el valor del parámetro ApiKey:

Parameter ApiKey = "myRandomApiKeyValue";

 

Ahora si NO queremos que se aplique la seguridad por api-key a todos los endpoints sobreescribimos el metodo MustCheckApiKey, en mi caso se da la coincidencia que las peticiones GET son públicas y las POST privadas por lo que lo he sobrescrito así:

ClassMethod MustCheckApiKey(pUrl As %String, pMethod As %String) As %Boolean
{
  SET res = 1
  If (pMethod="GET")
  {
      Set res=0
  }

  Quit res
}

 

Y listo! ya tenemos nuestros endpoints protegidos por un api-key.

Os dejo unas capturas de como se vería un petición bloqueada y una correcta:

 

Con api-key correcto:

 

Con un api-key incorrecto o inexistente:

 

Y aqui un prueba de una petición GET que sin api-key funciona ok:

 

Fichero Base.cls completo (por si queréis copiar y pegar)

 
Base.cls

 

 

Espero que os pueda ser útil en vuestros proyectos. 

 

Ya podemos sentarnos a disfrutar de nuestra nueva seguridad:

 

 

Gracias por leerme!

Comentarios (5)2
Inicie sesión o regístrese para continuar