Compartilhar via


Autenticação básica no ASP.NET Web API

por Mike Wasson

A autenticação básica é definida no RFC 2617, Autenticação HTTP: Autenticação de Acesso Básica e Digest.

Desvantagens

  • As credenciais do usuário são enviadas na solicitação.
  • As credenciais são enviadas como texto não criptografado.
  • As credenciais são enviadas a cada solicitação.
  • Não é possível fazer logoff, exceto encerrando a sessão do navegador.
  • Vulnerável à CSRF (solicitação intersite forjada); requer medidas anti-CSRF.

Vantagens

  • Padrão da Internet.
  • Compatível com todos os principais navegadores.
  • Protocolo relativamente simples.

A autenticação básica funciona da seguinte maneira:

  1. Se uma solicitação exigir autenticação, o servidor retornará 401 (Não autorizado). A resposta inclui um cabeçalho WWW-Authenticate, indicando que o servidor dá suporte à autenticação Básica.
  2. O cliente envia outra solicitação, com as credenciais do cliente no cabeçalho Autorização. As credenciais são formatadas como a cadeia de caracteres "name:password", codificada em base64. As credenciais não são criptografadas.

A autenticação básica é executada dentro do contexto de um "realm". O servidor inclui o nome do realm no cabeçalho WWW-Authenticate. As credenciais do usuário são válidas dentro desse realm. O escopo exato de um realm é definido pelo servidor. Por exemplo, você pode definir vários realms para particionar recursos.

Diagrama de autenticação básica

Como as credenciais são enviadas descriptografadas, a autenticação básica só é segura via HTTPS. Consulte Trabalhando com SSL na API Web.

A autenticação básica também é vulnerável a ataques CSRF. Depois que o usuário insere credenciais, o navegador as envia automaticamente em solicitações subsequentes para o mesmo domínio, durante a sessão. Isso inclui solicitações AJAX. Consulte Prevenção de ataques CSRF (solicitação intersite forjada).

Autenticação básica com o IIS

O IIS dá suporte à autenticação Básica, mas há uma ressalva: o usuário é autenticado em suas credenciais do Windows. Isso significa que o usuário deve ter uma conta no domínio do servidor. Para um site voltado para o público, você normalmente deseja se autenticar em um provedor de associação ASP.NET.

Para habilitar a autenticação básica usando o IIS, defina o modo de autenticação como "Windows" no Web.config do projeto ASP.NET:

<system.web>
    <authentication mode="Windows" />
</system.web>

Nesse modo, o IIS usa credenciais do Windows para autenticar. Além disso, você deve habilitar a autenticação Básica no IIS. No Gerenciador do IIS, acesse Exibição de Recursos, selecione Autenticação e habilite a autenticação Básica.

Imagem do II S Manager dashboard

Em seu projeto de API Web, adicione o atributo para todas as [Authorize] ações do controlador que precisam de autenticação.

Um cliente se autentica definindo o cabeçalho De autorização na solicitação. Os clientes do navegador executam essa etapa automaticamente. Os clientes Nonbrowser precisarão definir o cabeçalho.

Autenticação básica com associação personalizada

Conforme mencionado, a Autenticação Básica incorporada ao IIS usa credenciais do Windows. Isso significa que você precisa criar contas para seus usuários no servidor de hospedagem. Mas, para um aplicativo da Internet, as contas de usuário normalmente são armazenadas em um banco de dados externo.

O código a seguir como um módulo HTTP que executa a Autenticação Básica. Você pode conectar facilmente um provedor de associação ASP.NET substituindo o CheckPassword método , que é um método fictício neste exemplo.

Na API Web 2, você deve considerar escrever um filtro de autenticação ou um middleware OWIN, em vez de um módulo HTTP.

namespace WebHostBasicAuth.Modules
{
    public class BasicAuthHttpModule : IHttpModule
    {
        private const string Realm = "My Realm";

        public void Init(HttpApplication context)
        {
            // Register event handlers
            context.AuthenticateRequest += OnApplicationAuthenticateRequest;
            context.EndRequest += OnApplicationEndRequest;
        }

        private static void SetPrincipal(IPrincipal principal)
        {
            Thread.CurrentPrincipal = principal;
            if (HttpContext.Current != null)
            {
                HttpContext.Current.User = principal;
            }
        }

        // TODO: Here is where you would validate the username and password.
        private static bool CheckPassword(string username, string password)
        {
            return username == "user" && password == "password";
        }

        private static void AuthenticateUser(string credentials)
        {
            try
            {
                var encoding = Encoding.GetEncoding("iso-8859-1");
                credentials = encoding.GetString(Convert.FromBase64String(credentials));

                int separator = credentials.IndexOf(':');
                string name = credentials.Substring(0, separator);
                string password = credentials.Substring(separator + 1);

                if (CheckPassword(name, password))
                {
                    var identity = new GenericIdentity(name);
                    SetPrincipal(new GenericPrincipal(identity, null));
                }
                else
                {
                    // Invalid username or password.
                    HttpContext.Current.Response.StatusCode = 401;
                }
            }
            catch (FormatException)
            {
                // Credentials were not formatted correctly.
                HttpContext.Current.Response.StatusCode = 401;
            }
        }

        private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
        {
            var request = HttpContext.Current.Request;
            var authHeader = request.Headers["Authorization"];
            if (authHeader != null)
            {
                var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);

                // RFC 2617 sec 1.2, "scheme" name is case-insensitive
                if (authHeaderVal.Scheme.Equals("basic",
                        StringComparison.OrdinalIgnoreCase) &&
                    authHeaderVal.Parameter != null)
                {
                    AuthenticateUser(authHeaderVal.Parameter);
                }
            }
        }

        // If the request was unauthorized, add the WWW-Authenticate header 
        // to the response.
        private static void OnApplicationEndRequest(object sender, EventArgs e)
        {
            var response = HttpContext.Current.Response;
            if (response.StatusCode == 401)
            {
                response.Headers.Add("WWW-Authenticate",
                    string.Format("Basic realm=\"{0}\"", Realm));
            }
        }

        public void Dispose() 
        {
        }
    }
}

Para habilitar o módulo HTTP, adicione o seguinte ao arquivo web.config na seção system.webServer :

<system.webServer>
    <modules>
      <add name="BasicAuthHttpModule" 
        type="WebHostBasicAuth.Modules.BasicAuthHttpModule, YourAssemblyName"/>
    </modules>

Substitua "YourAssemblyName" pelo nome do assembly (sem incluir a extensão "dll").

Você deve desabilitar outros esquemas de autenticação, como Formulários ou Autenticação do Windows.