Autenticación AngularJS $ http, CORS y http

87

Debido a que usar CORS y autenticación http con AngularJS puede ser complicado, edité la pregunta para compartir una lección aprendida. Primero quiero agradecer a igorzg. Su respuesta me ayudó mucho. El escenario es el siguiente: desea enviar una solicitud POST a un dominio diferente con el servicio AngularJS $ http. Hay varias cosas complicadas que debe tener en cuenta al obtener AngularJS y la configuración del servidor.

Primero: en la configuración de su aplicación, debe permitir la llamada entre dominios

/**
 *  Cors usage example. 
 *  @author Georgi Naumov
 *  gonaumov@gmail.com for contacts and 
 *  suggestions. 
 **/ 
app.config(function($httpProvider) {
    //Enable cross domain calls
    $httpProvider.defaults.useXDomain = true;
});

Segundo: debe especificar withCredentials: true y nombre de usuario y contraseña en la solicitud.

 /**
  *  Cors usage example. 
  *  @author Georgi Naumov
  *  gonaumov@gmail.com for contacts and 
  *  suggestions. 
  **/ 
   $http({
        url: 'url of remote service',
        method: "POST",
        data: JSON.stringify(requestData),
        withCredentials: true,
        headers: {
            'Authorization': 'Basic bashe64usename:password'
        }
    });

Tercero: Configuración del servidor. Debes proveer:

/**
 *  Cors usage example. 
 *  @author Georgi Naumov
 *  [email protected] for contacts and 
 *  suggestions. 
 **/ 
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Origin: http://url.com:8080");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");

Para cada solicitud. Cuando reciba OPCIÓN debe aprobar:

/**
 *  Cors usage example. 
 *  @author Georgi Naumov
 *  gonaumov@gmail.com for contacts and 
 *  suggestions. 
 **/ 
if($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
   header( "HTTP/1.1 200 OK" );
   exit();
}

La autenticación HTTP y todo lo demás viene después de eso.

Aquí hay un ejemplo completo del uso del lado del servidor con php.

<?php
/**
 *  Cors usage example. 
 *  @author Georgi Naumov
 *  gonaumov@gmail.com for contacts and 
 *  suggestions. 
 **/ 
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Origin: http://url:8080");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");

if($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
   header( "HTTP/1.1 200 OK" );
   exit();
}


$realm = 'Restricted area';

$password = 'somepassword';

$users = array('someusername' => $password);


if (isset($_SERVER['PHP_AUTH_USER']) == false ||  isset($_SERVER['PHP_AUTH_PW']) == false) {
    header('WWW-Authenticate: Basic realm="My Realm"');

    die('Not authorised');
}

if (isset($users[$_SERVER['PHP_AUTH_USER']]) && $users[$_SERVER['PHP_AUTH_USER']] == $password) 
{
    header( "HTTP/1.1 200 OK" );
    echo 'You are logged in!' ;
    exit();
}
?>

Hay un artículo en mi blog sobre este tema que se puede ver aquí .

Georgi Naumov
fuente
La pregunta está editada.
Georgi Naumov
2
Estoy un poco confundido, es angularjs pero lo tienes envuelto en etiquetas PHP ... ¿me perdí algo?
onaclov2000
Este es solo un ejemplo de la lógica del lado del servidor. El texto debajo de "Тtercero: configuración del servidor" es la lógica del lado del servidor.
Georgi Naumov
@ onaclov2000 AngularJS es para el lado del cliente. Esto puede hablar con cualquier servidor, PHP, Ruby, Perl, Python, Java, JavaScript ... Podría continuar ..
Eric Hodonsky
1
¿Es esta una pregunta? Es más como una buena respuesta :)
Mohammad Kermani

Respuestas:

43

No, no tienes que poner credenciales, tienes que poner encabezados en el lado del cliente, por ejemplo:

 $http({
        url: 'url of service',
        method: "POST",
        data: {test :  name },
        withCredentials: true,
        headers: {
                    'Content-Type': 'application/json; charset=utf-8'
        }
    });

Y en el lado del servidor, debe poner encabezados a este es un ejemplo para nodejs:

/**
 * On all requests add headers
 */
app.all('*', function(req, res,next) {


    /**
     * Response settings
     * @type {Object}
     */
    var responseSettings = {
        "AccessControlAllowOrigin": req.headers.origin,
        "AccessControlAllowHeaders": "Content-Type,X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5,  Date, X-Api-Version, X-File-Name",
        "AccessControlAllowMethods": "POST, GET, PUT, DELETE, OPTIONS",
        "AccessControlAllowCredentials": true
    };

    /**
     * Headers
     */
    res.header("Access-Control-Allow-Credentials", responseSettings.AccessControlAllowCredentials);
    res.header("Access-Control-Allow-Origin",  responseSettings.AccessControlAllowOrigin);
    res.header("Access-Control-Allow-Headers", (req.headers['access-control-request-headers']) ? req.headers['access-control-request-headers'] : "x-requested-with");
    res.header("Access-Control-Allow-Methods", (req.headers['access-control-request-method']) ? req.headers['access-control-request-method'] : responseSettings.AccessControlAllowMethods);

    if ('OPTIONS' == req.method) {
        res.send(200);
    }
    else {
        next();
    }


});
igorzg
fuente
con CORS en general, ¿el servidor tiene que permitir todos los encabezados (Contenido, Longitud de contenido, Referer, etc.) presentes en la solicitud real, es decir, sin OPCIONES?
Kevin Meredith
@KevinMeredith No, no tiene que permitir todos los encabezados, puede permitir solo lo que necesita e incluso puede limitar también a un dominio.
igorzg
1
como se lo que necesito
Kevin Meredith
Gracias por tu buena respuesta :)
Kamruzzaman
1
Estoy confundido, ¿por qué no necesito autenticarme con el punto final si está protegido por una autenticación básica http?
Maxim Zubarev
3

Para realizar una solicitud CORS, uno debe agregar encabezados a la solicitud junto con los mismos que necesita para verificar que mode_header esté habilitado en Apache.

Para habilitar encabezados en Ubuntu:

sudo a2enmod headers

Para que el servidor php acepte solicitudes de diferentes orígenes, use:

Header set Access-Control-Allow-Origin *
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE"
Header always set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, client-security-token"
Vijay Kumar
fuente