Como evitar que o navegador invoque o pop-up de autenticação básico e manipule o erro 401 usando Jquery?


107

Preciso enviar um pedido de autorização usando autenticação básica. Eu implementei isso com sucesso usando jquery. No entanto, quando recebo o erro 401, o pop-up do navegador de autenticação básica é aberto e o retorno de chamada de erro do jquery ajax não é chamado.


Respostas:


46

Eu também estava enfrentando esse problema recentemente. Como você não pode alterar o comportamento padrão do navegador de mostrar o pop-up no caso de uma 401( autenticação básica ou digest ), existem duas maneiras de corrigir isso:

  • Altere a resposta do servidor para não retornar a 401. Em 200vez disso, retorne um código e trate-o em seu cliente jQuery.
  • Altere o método que você está usando para autorização para um valor personalizado em seu cabeçalho. Os navegadores exibirão o pop-up para Basic e Digest . Você deve alterar isso no cliente e no servidor.

    headers : {
      "Authorization" : "BasicCustom"
    }

Por favor, também dê uma olhada este para um exemplo de como usar jQuery com Auth Basic.


10
WWW-Authenticate: xBasic realm = com.example pode fazer isso, junto com o código de status 401 clássico. esta postagem do blog me mostrou a dica (eu não sou o dono do blog) loudvchar.blogspot.ca/2010/11/…
— PM

2
@PM, a resposta do blog é uma solução perfeita. Observe que se estiver usando, <security:http-basic/>você não precisa definir, basicAuthenticationFiltermas deve defini-lo como <security:http-basic entry-point-ref="myBasicAuthenticationEntryPoint"/>.
— Brett Ryan

Por favor, você pode me dizer como substituir a resposta antes de enviar de volta para o cliente, estou usando jaxrs com autenticação básica. qual classe eu preciso substituir para modificar a resposta?
— Mohammed Sameen

Por algum motivo, estou recebendo o pop-up ao retornar um 401e WWW-Authenticate:Bearer WWW-Authenticate:NTLM WWW-Authenticate:NegotiateVocê sabe por que seria
— DevEng

34

Retorne um código de status 400 genérico e, em seguida, processe esse lado do cliente.

Ou você pode manter o 401 e não retornar o cabeçalho WWW-Authenticate, que é realmente o que o navegador está respondendo com o pop-up de autenticação. Se o cabeçalho WWW-Authenticate estiver ausente, o navegador não solicitará as credenciais.


6
@MortenHaraldsen Bem, a resposta 401 é a resposta adequada a dar nesta ocasião, o problema é que o navegador está lidando com isso automaticamente de forma nativa, em vez de permitir que o aplicativo javascript faça isso. Você pode manter o padrão, não retornando a resposta adequada que o padrão recomenda, ou pode escolher não manter o padrão, retornando o código de resposta recomendado pelo padrão. Faça sua escolha :)
— Ibraheem

Em meu aplicativo expresso, res.removeHeader('www-authenticate'); // prevents browser from popping up a basic auth window.
— corrigi

1
@Ibraheem, eu não poderia ter dito melhor. Os padrões são criados por pessoas que sentam e conversam, não necessariamente aquelas que sentam e codificam.
— user2867288 01 de

15

Você pode suprimir o pop-up de autenticação básico com url de solicitação semelhante a este:

https://username:password@example.com/admin/...

Se você obtiver o erro 401 (nome de usuário ou senha incorretos), ele será tratado corretamente com o retorno de chamada de erro do jquery. Isso pode causar alguns problemas de segurança (no caso do protocolo http em vez de https), mas funciona.

UPD: o suporte desta solução será removido no Chrome 59


SURPREENDENTE!!!! Resolvi meu problema porque o problema estava tentando 192.168.1.1 e o roteador pedia o Auth.
— Nadav Lebovitch

Se você acessar a guia "Rede" nas ferramentas do desenvolvedor, em qualquer navegador, poderá ler o nome de usuário e a senha em texto simples. Mas funciona.
— Bruno Finger

19
Nunca faça isso, os logs de solicitações no seu servidor web são muito mais valiosos para mim agora. Combinações gratuitas de nomes de usuário e senha mais o código de resposta! Obrigado
— Remco

mas como alguém pode impedir que o nome de usuário e a senha sejam vistos
— sdx11

3
Este método de autenticação está se tornando obsoleto e o Chrome deixará de oferecer suporte para credenciais incorporadas, ou seja, https://user:pass@host/no M59 por volta de junho de 2017. Veja esta postagem do blog chromestatus para mais informações.
— Garywoo

13

Como outros apontaram, a única maneira de alterar o comportamento do navegador é garantir que a resposta não contenha um código de status 401 ou, se contiver, não inclua o WWW-Authenticate: Basiccabeçalho. Como alterar o código de status não é muito semântico e indesejável, uma boa abordagem é remover o WWW-Authenticatecabeçalho. Se você não pode ou não deseja modificar seu aplicativo de servidor web, você sempre pode servir ou proxy através do Apache (se você ainda não estiver usando o Apache).

Aqui está uma configuração para o Apache reescrever a resposta para remover o cabeçalho WWW-Authenticate IFF que a solicitação contém contém o cabeçalho X-Requested-With: XMLHttpRequest(que é definido por padrão pelas principais estruturas Javascript, como JQuery / AngularJS, etc ...) E a resposta contém o cabeçalho WWW-Authenticate: Basic.

Testado em Apache 2.4 (não tenho certeza se funciona com 2.2). Isso depende do mod_headersmódulo que está sendo instalado. (No Debian / Ubuntu, sudo a2enmod headerse reinicie o Apache)

    <Location />
            # Make sure that if it is an XHR request,
            # we don't send back basic authentication header.
            # This is to prevent the browser from displaying a basic auth login dialog.
            Header unset WWW-Authenticate "expr=req('X-Requested-With') == 'XMLHttpRequest' && resp('WWW-Authenticate') =~ /^Basic/"
    </Location>   

1
Para fazer o mesmo com o Nginx, definaproxy_hide_header WWW-Authenticate;
— Cuga

7

Use X-Requested-With: XMLHttpRequest com seu cabeçalho de solicitação. Portanto, o cabeçalho da resposta não conterá WWW-Authenticate: Basic.

beforeSend: function (xhr) {
                    xhr.setRequestHeader('Authorization', ("Basic "
                        .concat(btoa(key))));
                    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                },

1
Isso não teve nenhum efeito para mim. Que tipo de servidor você está usando que o WWW-Authenticate não é enviado incluído quando você define XMLHttpRequest?
— Robert Antonucci,

@RobertAntonucci é apache tomcat
— sedhu

5

Se estiver usando um servidor IIS, você pode configurar a regravação de URL do IIS (v2) para reescrever o WWW-Authenticationcabeçalho Noneno URL solicitado.

Guia aqui .

O valor que você deseja alterar é response_www_authenticate.

Se precisar de mais informações, adicione um comentário e postarei o arquivo web.config.


1
Isso funcionou muito bem. Gostaria de observar que a parte "resposta" deve ser escrita como "RESPONSE_www_authenticate" em URL Rewrite v2 no IIS 7.5.
— Michael Freeman de

3

Se o cabeçalho WWW-Authenticate for removido, você não obterá o cache de credenciais e não receberá de volta o cabeçalho Authorization na solicitação. Isso significa que agora você terá que inserir as credenciais para cada nova solicitação gerada.


Isso é muito importante, absolutamente correto.
— Tez Wingfield de

2

Como alternativa, se você pode personalizar a resposta do servidor, você pode retornar um 403 Forbidden.

O navegador não abrirá o pop-up de autenticação e o retorno de chamada do jquery será chamado.


5
Isso vai contra a especificação HTTP 1.1, onde se afirma que "... a autorização não ajudará e a solicitação NÃO DEVE ser repetida".
— Jukka Dahlbom

1
É válido receber 403 enquanto é autenticado para recursos aos quais você não tem permissão de acesso, 401 deve ser enviado para onde você ainda não foi autenticado.
— Brett Ryan

1

No Safari, você pode usar solicitações síncronas para evitar que o navegador exiba o pop-up. Obviamente, as solicitações síncronas só devem ser usadas neste caso para verificar as credenciais do usuário ... Você pode usar essa solicitação antes de enviar a solicitação real, o que pode causar uma experiência ruim para o usuário se o conteúdo (enviado ou recebido) for muito pesado.

    var xmlhttp=new XMLHttpRequest;
    xmlhttp.withCredentials=true;
    xmlhttp.open("POST",<YOUR UR>,false,username,password);
    xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    xmlhttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest');

Em outros contextos, usar "OPÇÕES" em vez de "POST" também pode ajudar.
— Emmanuel Sellier

0

Faça um / login url, aceite os parâmetros "usuário" e "senha" via GET e não exija autenticação básica. Aqui, use php, node, java, qualquer coisa e analise seu arquivo passwd e combine os parâmetros (user / pass) com ele. Se houver uma correspondência, redirecione para http: // user: pass@domain.com/ (isso definirá a credencial em seu navegador); caso contrário, envie uma resposta 401 (sem o cabeçalho WWW-Authenticate).


Isso seria ótimo para qualquer pessoa tentando detectar nomes de usuário / senhas de ataques de man in the middle-text!
— Ajax de

0

No verso do Spring Boot, usei BasicAuthenticationEntryPoint personalizado:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and().authorizeRequests()
            ...
            .antMatchers(PUBLIC_AUTH).permitAll()
            .and().httpBasic()
//    https://www.baeldung.com/spring-security-basic-authentication
            .authenticationEntryPoint(authBasicAuthenticationEntryPoint())
            ...

@Bean
public BasicAuthenticationEntryPoint authBasicAuthenticationEntryPoint() {
    return new BasicAuthenticationEntryPoint() {
        {
            setRealmName("pirsApp");
        }

        @Override
        public void commence
                (HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx)
                throws IOException, ServletException {
            if (request.getRequestURI().equals(PUBLIC_AUTH)) {
                response.sendError(HttpStatus.PRECONDITION_FAILED.value(), "Wrong credentials");
            } else {
                super.commence(request, response, authEx);
            }
        }
    };
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.