¿Cómo hacer un GET privado para una API?

varuk

Buenas.

A ver si sé explicar mi idea. Yo tengo un framework PHP que me permite hacer las rutas, tal que así:

$app->get('/', function() use ($var) {
     // body here
 });

Dentro de ese GET, junto con otros, supongamos que se devuelve un JSON y así pues vamos creando la API ¿no? Mi duda es ¿cuál es la mejor forma de que el acceso sea privado?

Es decir, yo había pensado en algo como una api key, que compruebe si esa API KEY está en la base de datos del servidor y en ese caso que devuelva el JSON y si no que de error. El caso es que me parece poco elegante tener que hacer eso en cada GET que implemente de cada ruta. Vamos, repetir ese código, o aunque sea un simple IF-ELSE dentro de cada ruta.

Para los entendidos en APIs, ¿hay alguna forma de hacerlo de forma elegante sin tener que mantener cookies o sesiones?

Uso el framework Silex, de PHP.

Gracias : )

Foxandxss

100% seguro que ese "Silex" tiene algún sistema de autentificación.

iRoN-G

En la API de Blizzard, que es con la que trabajo, utilizan Mashery y OAuth. Una vez identificado, tienes que generar un token que posteriormente utilizas en cada GET.

r2d2rigo

Pero vamos a ver, que esta preguntando como hacer la comprobacion de API key de una forma generica sin tener que hacer copy paste de la comprobacion en los callbacks de todos los endpoints, no os vayais por las ramas con que meta OAuth o un sistema de login completo.

#1 no tengo ni idea de como va tu framework, pero en ASP .NET esto se hace con Http Filters, que son un cacho de codigo que se lanza siempre justo antes de procesar la peticion y sirve para modificar/comprobar ciertas cosa de manera generica para todas la peticiones. Mirando la documentacion de Silex he visto que existe la Global Configuration, que viene a ser algo parecido: http://silex.sensiolabs.org/doc/usage.html#global-configuration

Dentro de eso tienes la llamada a before, que en la documentacion lo llaman "middlewares". Analiza ahi si el header que usas para la API Key es correcto y si no pues devuelves un codigo 401/403: http://silex.sensiolabs.org/doc/middlewares.html

2 respuestas
B

Tienes mil formas de hacerlo, probáblemente la más sencilla es incluir en la cabecera de la petición la la api key tipo "X-miserviceio-Auth: sdsdasd.asdkajshgdasd-asdasd". Luego ya si quieres más seguridad tira de oauth, etc.

1 respuesta
ZaO

Yo utilizo JWT, y puedes comprobar la auth del token con un middleware que le pases al controlador como un closure y así no lo repites...

Merkury

Create una configuracion con las keys y genera tokens. Yo lo que hice fue tambien crear una interfaz vacia que se llama TokenAuthenticatedController simplemente para poder capturar los controllers y un Listener y fiesta:

class TokenListener
{
    private $tokens;

public function __construct($tokens)
{
    $this->tokens = $tokens;
}

public function onKernelController(FilterControllerEvent $event)
{
    $controller = $event->getController();
    /*
     * $controller passed can be either a class or a Closure. This is not usual in Symfony2 but it may happen.
     * If it is a class, it comes in array format
     */
    if (!is_array($controller)) {
        return;
    }
    if ($controller[0] instanceof TokenAuthenticatedController) {
        $token = $event->getRequest()->headers->get('secretHash');
        if($event->getRequest()->headers->get('secretClient') != null || $event->getRequest()->headers->get('secretClient') != ''){
            $tokenPublic = $event->getRequest()->headers->get('secretClient');
        }
        else{
            $tokenPublic = null;
        }

        if(!$tokenPublic){
            throw new AccessDeniedHttpException('This action needs a valid token!');
        }

        $routeParams = $event->getRequest()->get('_route_params');
        unset($routeParams['_locale']);
        $routeValues = array_values($routeParams);

        $seed = '';
        /*In the original file here is the place where the encriptyon/decryption have place, but I removed it for obvious reasons :) */
        if ($token != $checkHash) {
            throw new AccessDeniedHttpException('This action needs a valid token!');
        }
    }
}
Fastestwat

Esta pregunta ya te fue contestada hace cosa de un mes.

Silex oauth2 google

Creo que fuiste tú quien puso una pagina muy interesante sobre design patterns y demás con unas recomendaciones. Revísalo tb

1 respuesta
Merkury

#8 Me gustaria saber el tamaño y el alcance de la API que esta montando, pero me parece un overkill interesante meter OAuth. Especialmente si la API va a ser consumida por otros servicios, apps, etc.

2 respuestas
Fastestwat

#4 #9 estoy de acuerdo con los dos pero como hace un mes le dije que mirara tokens y vuelve ahora con que el problema es que le parece poco elegante...

Before como comenta #4 sería lo suyo y eso se puede hacer aplicando un design pattern de los que puso él en otra pág.

Conclusión le he dicho oAuth porque encontrara ya cosas montadas. Respondiendo a #9 añades un nuevo cliente al oAuth y pista

2 respuestas
Merkury

#10 Dile que OAuth usa tokens igual y graba su reacción please.

varuk

En primer lugar gracias a todos y perdón por responder tan tarde. No esperaba que el hilo fuera a provocar tanta expectación. ^^

#9 #10 Bueno, en primer lugar decir que lo que estoy haciendo es una simple aplicación para Android, no tiene más misterio (por aprender Android), que se comunica con la API de la que hablo. Así que no hace falta gran seguridad, sólo que en cada GET se mande un "hash", o una key api, y si es esa la correcta pues que devuelva el JSON correspondiente de la consulta (que no es más que una lista de conciertos de música de la ciudad y esas cosas).

#10 Lo que comentas de hace un mes era un tema diferente, si mal no recuerdo, pero sí era parecido.

#4 mmm creo que eso era lo que buscaba. Hacer algo así, como dices tú:

$app->get('/', function() use ($app) { (//aquí código de la función })
    ->before($setup);

$app->get('/login', function() use ($app) { //aquí el código de la función })
    ->before($setup);

Tener un middleware before que compruebe. Lo que no sé es como trabaja esto internamente, ya que en mi vida he trabajado con Frameworks de estos. No sé cómo sabe esto, si dentro del "before" la api key no fuera válida, que tiene que devolver un JSON con error. Luego me leeré la documentación o buscaré ejemplos. No sé si en el before. Quiero ver el ciclo que tiene desde que llega la llamada al GET hasta que va pasando por los before y todo eso para entenderlo y así poder hacerlo.

Muchas gracias ^^

#5 Sí, eso había pensando, la cosa era más de llevar a código eso. Nunca he trabajado con todo esto y ahora mismo para mi todo esto de las cabeceras y enviar cosas me pilla un poco... De teoría bien pero en la práctica voy a tener que ir mirando cosas para implementarlo.

Aunque mi intención es más el lado de Android, cualquier consejo o recurso para meterme un poco con esto, ya que me pongo aprendo, será muy bienvenido, por supuesto.

Se agradece la ayuda siempre.

1 respuesta
Fastestwat

#12 Tranqui, cualquier cosa nos dices. La mejor opción si solo quieres probar eso es un before.

Del lado de Android espero que estés usando Retrofit o Volley. Mejor Retrofit.

1 respuesta
varuk

#13 Sí, estoy usando Retrofit. Ya lo he usado para otras cosas. Gracias ^^

Usuarios habituales