javascript - missing - ¿Por qué la solicitud de OPT de verificación previa de una solicitud CORS autenticada funciona en Chrome pero no en Firefox?
enable cors (2)
Estoy escribiendo un cliente de JavaScript para ser incluido en sitios de terceros (piense en el botón Me gusta de Facebook). Necesita recuperar información de una API que requiere autenticación HTTP básica. La configuración simplificada se ve así:
Un sitio de terceros incluye este fragmento en su página:
<script
async="true"
id="web-dev-widget"
data-public-key="pUbl1c_ap1k3y"
src="http://web.dev/widget.js">
</script>
widget.js llama a la API:
var el = document.getElementById(''web-dev-widget''),
user = ''token'',
pass = el.getAttribute(''data-public-key''),
url = ''https://api.dev/'',
httpRequest = new XMLHttpRequest(),
handler = function() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
console.log(httpRequest.responseText);
} else {
console.log(''There was a problem with the request.'', httpRequest);
}
}
};
httpRequest.open(''GET'', url, true, user, pass);
httpRequest.onreadystatechange = handler;
httpRequest.withCredentials = true;
httpRequest.send();
La API se configuró para responder con los encabezados apropiados:
Header set Access-Control-Allow-Credentials: true
Header set Access-Control-Allow-Methods: "GET, OPTIONS"
Header set Access-Control-Allow-Headers: "origin, authorization, accept"
SetEnvIf Origin "http(s)?://(.+?/.[a-z]{3})$" AccessControlAllowOrigin=$0
Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Tenga en cuenta que Access-Control-Allow-Origin
está configurado en el Origin
lugar de usar un comodín porque estoy enviando una solicitud con credenciales ( withCredentials
).
Todo está ahora en su lugar para realizar una solicitud autenticada entre dominios sincrónica, y funciona de maravilla en Chrome 25 en OS X 10.8.2. En Dev Tools, puedo ver la solicitud de red para la solicitud OPTIONS
antes de la solicitud GET
, y la respuesta vuelve como se esperaba.
Cuando se prueba en Firefox 19, no aparecen solicitudes de red en Firebug a la API, y este error se registra en la consola: NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
Después de excavar mucho, descubrí que Gecko no permite que el nombre de usuario y la contraseña se encuentren directamente en un URI entre sitios de acuerdo con los comentarios. Supuse que esto era por usar los parámetros opcionales de usuario y contraseña para open()
así que probé con el otro método de realizar solicitudes autenticadas, que es codificar las credenciales en Base64 y enviar un encabezado de Autorización:
// Base64 from http://www.webtoolkit.info/javascript-base64.html
auth = "Basic " + Base64.encode(user + ":" + pass);
...
// after open() and before send()
httpRequest.setRequestHeader(''Authorization'', auth);
Esto da como resultado una respuesta 401 Unauthorized
a la solicitud OPTIONS
que conduce a búsquedas de Google como "¿Por qué funciona esto en Chrome y no en Firefox?" Fue entonces cuando supe que estaba en problemas.
¿ Por qué funciona en Chrome y no en Firefox? ¿Cómo puedo obtener la solicitud de OPTIONS
para enviar y responder de manera consistente?
Esta es una publicación anterior, pero tal vez esto podría ayudar a las personas a completar el problema CORS. Para completar el problema de autorización básica, debe evitar la autorización de solicitudes OPTIONS en su servidor. Este es un ejemplo de configuración de Apache. Simplemente agregue algo como esto en su VirtualHost o ubicación.
<LimitExcept OPTIONS>
AuthType Basic
AuthName <AUTH_NAME>
Require valid-user
AuthUserFile <FILE_PATH>
</LimitExcept>
¿ Por qué funciona en Chrome y no en Firefox?
La especificación W3 para las solicitudes de verificación previa de CORS establece claramente que las credenciales del usuario deben excluirse. Existe un error en Chrome y WebKit donde las solicitudes de OPTIONS
que devuelven un estado de 401 aún envían la solicitud subsiguiente.
Firefox tiene un archivo de errores relacionado que finaliza con un enlace a la lista de correo W3 public webapps solicitando que se cambie la especificación CORS para permitir el envío de encabezados de autenticación en la solicitud OPTIONS
en beneficio de los usuarios de IIS. Básicamente, están esperando que esos servidores se vuelvan obsoletos.
¿Cómo puedo obtener la solicitud de OPTIONS
para enviar y responder de manera consistente?
Simplemente haga que el servidor (API en este ejemplo) responda a las solicitudes OPTIONS
sin requerir autenticación.
Kinvey hizo un buen trabajo al expandir esto al mismo tiempo que se vinculaba a un problema de la API de Twitter que delineaba el problema de catch-22 de este escenario exacto, curiosamente un par de semanas antes de que se presentaran los problemas del navegador.