Autenticação básica de login e HTTP novamente

Os desenvolvedores da Web estão cientes do problema de efetuar logon e logon em sites protegidos pela HTTP Basic Authorization. Embora existam outros métodos de autenticação que não sofrem com esse problema, a Autorização Básica ainda é frequentemente a melhor opção. A rede possui materiais suficientes que descrevem várias soluções gerais e particulares. Mas todos eles, que encontrei, infelizmente, descrevem apenas algumas soluções parciais que funcionam em um navegador e não em outro. Sob gato, dou um resultado final generalizado da minha pesquisa sobre esse problema

Farei uma reserva imediatamente de que não sou desenvolvedor front-end e não mergulhei em toda a variedade de "marcas" e versões de navegadores. Somente mainstream com versões relevantes no momento da redação. Para a maioria das tarefas da Web, isso é suficiente. Para os desenvolvedores que precisam de suporte para todo o "zoológico" de navegadores, o artigo pode ser um bom ponto de partida:

a essência do problema é que o padrão de autorização básica de HTTP não fornece log. Geralmente. Quando você acessa uma página protegida pela Autorização Básica, o próprio navegador exibe sua própria janela com uma solicitação de login / senha e, com um login bem-sucedido, as salva em algum lugar profundo. Em seguida, todas as solicitações subsequentes para outras páginas protegidas deste site usarão automaticamente esses valores no cabeçalho da Autorização:
Autorização: Basic bm9uZTpub25l
onde bm9uZTpub25l é o link de login / senha codificado em base64 none: none (seu nome de usuário e senha podem ser diferentes)

Para fazer login, você só precisa redefinir o nome de usuário / senha antigo nessas profundidades do navegador e neles lugar para gravar novos. É aqui que uma surpresa nos espera. Como nenhum padrão regula essa ação, cada navegador faz isso de acordo com seu próprio entendimento.

Pior, como a janela de solicitação de login / senha é sua própria janela do navegador, que já responde apenas aos cabeçalhos de página HTTP, essa janela é exibida antes de qualquer processamento do corpo da página. Ou seja, executar algum javascript ao receber uma resposta do servidor com um status 401 não funciona. Antes do usuário, essa janela será exibida repetidas vezes com uma solicitação repetida de login / senha.

Na verdade, esse ponto é crítico, pois para quase todos os navegadores a única maneira de sair é enviar uma solicitação ao servidor com login / senha obviamente incorreta, receber uma resposta do servidor com o status 401 e redefinir o cache de login / senha do navegador. Mas se, ao mesmo tempo, o navegador não permitir que você processe a resposta 401 e continue o processo de login já para o novo usuário, assumindo o controle mesmo no estágio de leitura dos cabeçalhos HTTP e lançando a própria forma de autorização na qual você o digita não funcionará na sua cara, então isso já é um problema. Não importa se essa é uma solicitação normal por referência ou XMLHttpRequest ou busca. O navegador ainda assume o controle na fase de análise dos cabeçalhos.

Assim…

Dados iniciais:


  1. Há uma página logout.html separada, na qual toda a lógica está localizada no script javascript, partes das quais são fornecidas no decorrer da apresentação
  2. URL especificado - endereço da página a ser redirecionado após o login bem-sucedido
  3. Url401 é especificado - o endereço da página que sempre retorna o erro HTTP 401 (não autorizado)

// file logout.html
const url = new URL("http://mysite.com/");
const url401 = new URL("http://mysite.com/401");

Internet Explorer


Nosso produto não requer suporte para este navegador, portanto, a solução que eu não testei pessoalmente. No entanto, segundo o Google, existe uma solução para isso, e talvez seja o mais simples e mais elegante de todos. Além disso, nunca encontrei nenhuma informação de que essa solução para navegadores da Microsoft tenha perdido sua relevância:

if (document.execCommand("ClearAuthenticationCache")) {
    window.location.assign(url);
}

No IE, existe um método ClearAuthenticationCache que descarta "esses intestinos muito profundos". Simples e elegante. E nada de dançar com a página auxiliar 401. Não sei se esse método funciona no Edge. Provavelmente sim.

A construção document.execCommand retorna true se o método existe e "funcionou". Então window.location.assign (url) redireciona o usuário para inserir um novo nome de usuário e senha

Firefox (72.0.1)


No contexto de nossa tarefa, este é o navegador mais problemático. Para ele, ainda não existe uma solução completa. Por 15 a 20 anos, uma solicitação para o problema indicado está pendurada no rastreador de erros da equipe de seus desenvolvedores. Mas "as coisas ainda estão lá". O máximo que pode ser alcançado é a curva razlogin.

Entrada: O
Firefox não libera o cache de senhas após receber uma resposta 401 por meio do XMLHttpRequest ou da solicitação de busca. Somente através de uma solicitação regular com o login / senha no próprio URL. Ou seja, algo como
http: // nenhum: none@meusite.com/
O código:

else if (/firefox|iceweasel|fxios/i.test(window.navigator.userAgent)) {
    url.username = 'none';
    url.password = 'none';
    window.location.assign(url);
}

Após o qual o usuário recebe um formulário de login / senha, no qual quer que você insira, ele será exibido novamente. O fato é que os valores inseridos não substituirão os valores de login / senha especificados na URL. Ou seja, em vez dos valores inseridos, um monte de nenhum: nenhum irá para o servidor a cada vez. E para fazer login com um nome diferente, o usuário deve clicar em cancelar, ir para a página inicial (http: //mysite.com/) e inserir um novo login / senha lá.

Torto? Mas, infelizmente, não há outra solução

Google Chrome (79.0.3945.88)


Para o Chrome, o método de busca funciona muito bem. Mas XMLHttpRequest não funciona (((o cache não está liberado e o log não ocorre. Além disso, tentei definir o login / senha como parâmetros para o método aberto e para definir o cabeçalho).

else if (/chrome/i.test(window.navigator.userAgent)) {
    fetch(url401, {
      credentials: 'include',
      headers: {
        'Authorization': 'Basic ' + btoa('none:none'),
        'X-Requested-With': 'XMLHttpRequest'
      }
    }).then(() => {
      window.location.assign(url);
    }).catch(err => console.error(err));
}

Fazemos uma solicitação de busca para a página 401 com nome de usuário / senha obviamente incorretos, obtemos uma resposta 401 do servidor, o navegador libera seu cache.

IMPORTANTE! O servidor NÃO deve retornar um cabeçalho WWW-Authenticate . Caso contrário, o navegador assumirá o controle e os redirecionamentos da página 401 nunca acontecerão. Por convenção, o servidor não deve retornar esse cabeçalho se X-Requested-With: XMLHttpRequest for especificado na solicitação . Portanto, o cabeçalho X-Requested-With foi adicionado à solicitação .

Safari (12)


Para o Safari, a situação é exatamente o oposto: XMLHttpRequest funciona, mas a busca não funciona

else {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url401, true, 'none', 'none');
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.onerror = function(err) {
      console.error(err);
    };
    xhr.onload = function () {
      window.location.assign(url);
    };
    xhr.send()
}

As ações são iguais às do Chrome, apenas através do XMLHttpRequest.

Deverá funcionar para as versões do Safari 6+. As versões anteriores tinham seus próprios bugs. Em particular, por exemplo, nas versões 5.1, com cada redirecionamento, o navegador solicitou forçosamente a autorização, razão pela qual a autorização com redirecionamento para a página final não funcionava em princípio. E nas versões anteriores à 5.0, o log não funcionava.

All Articles