Autenticação de usuário na API da Web do ASP.NET

150

Este tópico tem sido incrivelmente confuso para mim. Sou iniciante em aplicativos HTTP, mas preciso desenvolver um cliente do iPhone que consuma dados JSON de algum lugar. Eu escolhi a Web API da MS porque parecia bastante fácil, mas quando se trata de autenticar usuários, as coisas ficam bastante frustrantes.

Surpreende-me como não consegui encontrar um exemplo claro de como autenticar um usuário desde a tela de login até usar o Authorizeatributo nos meus ApiControllermétodos após várias horas pesquisando no Google.

Esta não é uma pergunta, mas uma solicitação de um exemplo de como fazer isso exatamente. Eu olhei para as seguintes páginas:

Embora eles expliquem como lidar com solicitações não autorizadas, elas não demonstram claramente algo parecido com LoginControlleralgo assim para solicitar credenciais do usuário e validá-las.

Alguém disposto a escrever um bom exemplo simples ou me indicar a direção certa, por favor?

Obrigado.

Luis Aguilar
fonte
1
Eu respondi o mesmo tipo de pergunta sobre este: stackoverflow.com/questions/11775594/...
cuongle
Para a API da Web com asp.net, você pode simplesmente usar o módulo de autenticação de cookie e forms como faria com um aplicativo mvc (se desejar). Portanto, no seu código de API da Web, você pode verificar o principal para ver se o usuário está logado, por exemplo (o mesmo de antes).
Elliot
Também olhar para a minha resposta para stackoverflow.com/questions/11775594/...
Varun Chatterji
Eu recomendo fortemente que muitas pessoas leiam o artigo asp.net/web-api/overview/security/… .
Youngjae

Respostas:

176

Surpreende-me como não consegui encontrar um exemplo claro de como autenticar um usuário desde a tela de login até o uso do atributo Authorize nos meus métodos ApiController após várias horas pesquisando no Google.

Isso ocorre porque você está ficando confuso com esses dois conceitos:

  • A autenticação é o mecanismo pelo qual os sistemas podem identificar com segurança seus usuários. Os sistemas de autenticação fornecem respostas para as perguntas:

    • Quem é o usuário?
    • O usuário é realmente quem ele / ela representa?
  • Autorização é o mecanismo pelo qual um sistema determina qual nível de acesso um usuário autenticado específico deve ter para proteger recursos controlados pelo sistema. Por exemplo, um sistema de gerenciamento de banco de dados pode ser projetado para fornecer a certos indivíduos especificados a capacidade de recuperar informações de um banco de dados, mas não a capacidade de alterar dados armazenados no banco de dados, enquanto oferece a outros indivíduos a capacidade de alterar dados. Os sistemas de autorização fornecem respostas para as perguntas:

    • O usuário X está autorizado a acessar o recurso R?
    • O usuário X está autorizado a executar a operação P?
    • O usuário X está autorizado a executar a operação P no recurso R?

O Authorizeatributo no MVC é usado para aplicar regras de acesso, por exemplo:

 [System.Web.Http.Authorize(Roles = "Admin, Super User")]
 public ActionResult AdministratorsOnly()
 {
     return View();
 }

A regra acima permitirá que apenas usuários nas funções de administrador e superusuário acessem o método

Essas regras também podem ser definidas no arquivo web.config, usando o locationelemento Exemplo:

  <location path="Home/AdministratorsOnly">
    <system.web>
      <authorization>
        <allow roles="Administrators"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>

No entanto, antes que essas regras de autorização sejam executadas, você deve estar autenticado no site atual .

Embora eles expliquem como lidar com solicitações não autorizadas, elas não demonstram claramente algo como um LoginController ou algo parecido para solicitar credenciais de usuário e validá-las.

A partir daqui, poderíamos dividir o problema em dois:

  • Autenticar usuários ao consumir os serviços de API da Web no mesmo aplicativo da Web

    Essa seria a abordagem mais simples, porque você confiaria na autenticação no ASP.Net

    Este é um exemplo simples:

    Web.config

    <authentication mode="Forms">
      <forms
        protection="All"
        slidingExpiration="true"
        loginUrl="account/login"
        cookieless="UseCookies"
        enableCrossAppRedirects="false"
        name="cookieName"
      />
    </authentication>
    

    Os usuários serão redirecionados para a rota da conta / login , onde você processaria controles personalizados para solicitar credenciais do usuário e, em seguida, você definiria o cookie de autenticação usando:

        if (ModelState.IsValid)
        {
            if (Membership.ValidateUser(model.UserName, model.Password))
            {
                FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                return RedirectToAction("Index", "Home");
            }
            else
            {
                ModelState.AddModelError("", "The user name or password provided is incorrect.");
            }
        }
    
        // If we got this far, something failed, redisplay form
        return View(model);
    
  • Autenticação multiplataforma

    Nesse caso, você estaria apenas expondo os serviços de API da Web no aplicativo Web; portanto, você teria outro cliente consumindo os serviços, o cliente poderia ser outro aplicativo da Web ou qualquer aplicativo .Net (Win Forms, WPF, console, serviço do Windows, etc)

    Por exemplo, suponha que você consumirá o serviço de API da Web de outro aplicativo Web no mesmo domínio de rede (dentro de uma intranet); nesse caso, você poderá confiar na autenticação do Windows fornecida pelo ASP.Net.

    <authentication mode="Windows" />

    Se seus serviços estiverem expostos na Internet, você precisará passar os tokens autenticados para cada serviço de API da Web.

    Para mais informações, consulte os seguintes artigos:

Jupaol
fonte
3
Uau! É o que chamo de resposta. Então, para concluir. Estou planejando fazer o seguinte: 1. Crie um controlador de conta com um método de Login que receba o nome de usuário e a senha por HTTPS e retorne o resultado do logon e o token. 2. O cliente armazena o token e o envia como um cabeçalho (sem mais HTTPS) na solicitação validada pelo servidor da web. Essa é uma boa abordagem? Então, minha dúvida final é como controlar a adulteração e expiração do token. Isso é possível?
44612 Luis Aguilar
6
@Jupaol Acho que falo com muitos desenvolvedores de APIs da Web, não posso usar a autenticação de formulários porque não tenho um site e os clientes não estão usando um navegador, nem posso usar a autenticação integrada porque os usuários podem estar em qualquer lugar do mundo em qualquer dispositivo ( daí a API da Web), então o que eu uso?
markmnl
21
Não entendo por que essa resposta recebe tantos votos. Não se trata da API da Web do ASP.NET, mas do ASP.NET MVC.
Bastien Vandamme
3
Gostaria de reiterar o comentário de B413 e apontar que esta pergunta solicita especificamente a API Web
Julien
6
Essa é a resposta 'errada' mais votada no SO? A resposta não fala sobre API Web, que é muito diferente de um aplicativo da web mvc! Como @ B413, estou totalmente chocado!
stt106
15

Se você deseja se autenticar com um nome de usuário e senha e sem um cookie de autorização , o atributo MVC4 Authorize não funcionará imediatamente . No entanto, você pode adicionar o seguinte método auxiliar ao seu controlador para aceitar cabeçalhos de autenticação básica. Chame desde o início dos métodos do seu controlador.

void EnsureAuthenticated(string role)
{
    string[] parts = UTF8Encoding.UTF8.GetString(Convert.FromBase64String(Request.Headers.Authorization.Parameter)).Split(':');
    if (parts.Length != 2 || !Membership.ValidateUser(parts[0], parts[1]))
        throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "No account with that username and password"));
    if (role != null && !Roles.IsUserInRole(parts[0], role))
        throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "An administrator account is required"));
}

Do lado do cliente, esse auxiliar cria um HttpClientcom o cabeçalho de autenticação no lugar:

static HttpClient CreateBasicAuthenticationHttpClient(string userName, string password)
{
    var client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(userName + ':' + password)));
    return client;
}
Edward Brey
fonte
Só queria comentar que eu estava procurando uma maneira simples de usar o padrão do setor para passar credenciais no cabeçalho. Este exemplo mostrou o básico do servidor e do lado do cliente e era tudo o que eu precisava.
21137 da_jokker
9

Estou trabalhando em um projeto de MVC5 / API da Web e precisava obter autorização para os métodos da API da Web. Quando minha exibição de índice é carregada pela primeira vez, faço uma chamada para o método da API da Web 'token' que acredito ser criado automaticamente.

O código do lado do cliente (CoffeeScript) para obter o token é:

getAuthenticationToken = (username, password) ->
    dataToSend = "username=" + username + "&password=" + password
    dataToSend += "&grant_type=password"
    $.post("/token", dataToSend).success saveAccessToken

Se for bem-sucedido, o seguinte é chamado, o que salva o token de autenticação localmente:

saveAccessToken = (response) ->
    window.authenticationToken = response.access_token

Então, se eu precisar fazer uma chamada do Ajax para um método de API da Web que tenha a tag [Authorize], basta adicionar o seguinte cabeçalho à minha chamada do Ajax:

{ "Authorization": "Bearer " + window.authenticationToken }
ProfNimrod
fonte
De onde response.access_tokenvem. Você está definindo isso a partir do código c # ..?
Shashwat
O objeto 'response' é retornado pelo método 'token'.
ProfNimrod
Eu não procurei papéis. Essa abordagem fornece apenas um token de acesso para que você possa chamar métodos WebApi decorados com a tag [Autorizar]. Presumivelmente, quando você chama qualquer um desses métodos, pode verificar as funções. stackoverflow.com/questions/19689570/mvc-5-check-user-role pode ajudar.
ProfNimrod
E onde nesta solução você realmente autentica seu usuário?
Craig Brett
O terminal / token é criado automaticamente para qualquer novo projeto de API da Web. O código por trás disso é onde o usuário é autenticado. É um pouco mais complicado se você adicionou um controlador de API da Web a um projeto MVC existente.
ProfNimrod 29/05