Como autenticar usuários com o .NET

O .NET torna fácil veicular um app da Web para muitos usuários autenticados. Com o Google Identity Platform, é fácil acessar informações sobre os usuários, garantindo que as credenciais de login deles sejam gerenciadas de forma segura pelo Google. O OAuth 2.0 facilita o fornecimento de um fluxo de login para todos os usuários do app e concede ao aplicativo o acesso a informações básicas de perfil sobre os usuários autenticados.

O código de amostra no app Bookshelf apresenta um exemplo de como criar um fluxo de login para usuários e como usar informações de perfil para oferecer uma funcionalidade personalizada aos usuários.

Esta página é parte de um tutorial com várias páginas. Para ver do início e ler as instruções de configuração, consulte o artigo App Bookshelf em .NET.

Sobre a autenticação do ASP.NET

Para que o aplicativo autentique os usuários, você precisa encontrar uma maneira de armazenar as informações do usuário atual.

O ASP.NET MVC inclui autenticação com cookies criptografados para armazenar as informações sobre o usuário atual. Configure a autenticação de cookies para usar um provedor de login externo, como o Google OAuth 2.0.

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ExternalCookie
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);

Autenticação de usuários

Autenticar o usuário envolve duas etapas principais, que, juntas, são chamadas de fluxo de serviço da Web. Essas etapas são:

  • Redirecionar o usuário para o serviço de autorização do Google.
  • Processar a resposta quando o Google redirecionar o usuário para o aplicativo.

O pacote Microsoft.Owin.Security.Google facilita a integração do OAuth2 ao seu aplicativo e dispensa a implementação do fluxo.

  1. Configure as opções de autenticação do Google OAuth 2.0 com o ID e a chave secreta do cliente:

    var authenticationOptions = new GoogleOAuth2AuthenticationOptions()
    {
        ClientId = LibUnityConfig.GetConfigVariable("GoogleCloudSamples:AuthClientId"),
        ClientSecret = LibUnityConfig.GetConfigVariable("GoogleCloudSamples:AuthClientSecret"),
    };
    

  2. Configure escopos para o serviço de autorização do Google.

    O aplicativo envia seu usuário para o serviço de autorização do Google. O URL é gerado usando o ID do cliente e os escopos utilizados pelo aplicativo. Os escopos indicam quais elementos das informações do usuário o aplicativo tem permissão para acessar. No Google existem vários serviços, com diferentes escopos para cada um. Por exemplo, há um escopo que permite acesso somente leitura ao Google Drive e outro que permite acesso para leitura e gravação. Esta amostra requer somente o escopo básico profile, que concede ao aplicativo acesso às informações básicas do perfil do usuário:

    // Add scope to access user's basic profile information
    authenticationOptions.Scope.Add("profile");
    
  3. Redirecione para fazer login na tela de consentimento do usuário no Google e redirecione de volta para a página inicial do aplicativo:

    public void Login()
    {
        // Redirect to the Google OAuth 2.0 user consent screen
        HttpContext.GetOwinContext().Authentication.Challenge(
            new AuthenticationProperties { RedirectUri = "/" },
            "Google"
        );
    }
    
  4. Processe a resposta de autorização.

    O Google envia o usuário de volta ao seu aplicativo com informações sobre o usuário. Por padrão, o Microsoft.Owin.Security.Google faz o login do usuário autenticado e fornece acesso ao nome do usuário e ao identificador exclusivo. Para acessar o URL da imagem de perfil do usuário, o callback OnAuthenticated lê esse URL na resposta do Google OAuth e o adiciona à identidade do usuário atual.

    // After OAuth authentication completes successfully,
    // read user's profile image URL from the profile
    // response data and add it to the current user identity
    OnAuthenticated = context =>
    {
        var profileUrl = context.User["image"]["url"].ToString();
        context.Identity.AddClaim(new Claim(ClaimTypes.Uri, profileUrl));
        return Task.FromResult(0);
    }
    

    Como resultado, o URL da imagem do perfil do usuário é acessível por meio da classe User do aplicativo.

        public class User : ClaimsPrincipal
        {
            public User(IPrincipal principal) : base(principal as ClaimsPrincipal) { }
    
            public string Name => this.Identity.Name;
            public string UserId => this.FindFirst(ClaimTypes.NameIdentifier).Value;
            public string ProfileImage => this.FindFirst(ClaimTypes.Uri).Value;
        }
    
  5. Crie uma maneira para os usuários saírem.

    public ActionResult Logout()
    {
        Request.GetOwinContext().Authentication.SignOut();
        return Redirect("/");
    }
    
  6. Use as informações de perfil fornecidas pelo usuário atual nos modelos.

    Para que as visualizações do aplicativo MVC acessem detalhes sobre o usuário conectado, o tipo de página básica do aplicativo precisa ser configurado para usar BookshelfWebViewPage, uma página básica de visualização que expõe o usuário atual.

    <pages pageBaseType="GoogleCloudSamples.Views.BookshelfWebViewPage">
    
    public abstract class BookshelfWebViewPage<TModel> : WebViewPage<TModel>
    {
        public User CurrentUser => new User(this.User);
    }
    
  7. Atualize a visualização do layout para indicar ao usuário se ele está conectado ou desconectado.

    <p class="navbar-text navbar-right">
        @if (Request.IsAuthenticated)
        {
            <img src="@CurrentUser.ProfileImage" class="img-circle" width="24">
            <span>
                @CurrentUser.Name
                &nbsp;
                @Html.ActionLink("(logout)", "Logout", "Session")
            </span>
        }
        else
        {
            @Html.ActionLink("Login", "Login", "Session")
        }
    </p>
    

Personalização

Com as informações de perfil do usuário conectado à sua disposição, é possível controlar qual usuário adicionou qual livro ao banco de dados.

        public async Task<ActionResult> Create(Book book, HttpPostedFileBase image)
        {
            if (ModelState.IsValid)
            {
                if (Request.IsAuthenticated)
                {
                    // Track the user who created this book
                    book.CreatedById = CurrentUser.UserId;
                }

                _store.Create(book);

                // ...

E como você tem essas informações no banco de dados, use-as para criar uma nova visualização que permite que um usuário veja todos os livros adicionados.

public ActionResult Mine(string nextPageToken)
{
    if (Request.IsAuthenticated)
    {
        return View("Index", new ViewModels.Books.Index()
        {
            // Fetch books created by the logged in user
            BookList = _store.List(_pageSize, nextPageToken, userId: CurrentUser.UserId)
        });
    }
    else
    {
        return RedirectToAction("Index");
    }
}

Cloud Datastore

Aplique as alterações de personalização do usuário ao Cloud Datastore.

public BookList List(int pageSize, string nextPageToken, string userId = null)
{
    var query = new Query("Book") { Limit = pageSize };
    if (userId != null)
        query.Filter = Filter.Equal("CreatedById", userId);
    if (!string.IsNullOrWhiteSpace(nextPageToken))
        query.StartCursor = ByteString.FromBase64(nextPageToken);
    var results = _db.RunQuery(query);
    return new BookList()
    {
        Books = results.Entities.Select(entity => entity.ToBook()),
        NextPageToken = results.Entities.Count == query.Limit ?
            results.EndCursor.ToBase64() : null
    };
}

Cloud SQL

Aplique as alterações de personalização do usuário ao Cloud SQL.

public BookList List(int pageSize, string nextPageToken, string userId = null)
{
    IQueryable<Book> query = _dbcontext.Books.OrderBy(book => book.Id);
    if (userId != null)
    {
        // Query for books created by the user
        query = query.Where(book => book.CreatedById == userId);
    }
    if (nextPageToken != null)
    {
        long previousBookId = long.Parse(nextPageToken);
        query = query.Where(book => book.Id > previousBookId);
    }
    var books = query.Take(pageSize).ToArray();
    return new BookList()
    {
        Books = books,
        NextPageToken = books.Count() == pageSize ? books.Last().Id.ToString() : null
    };
}
Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…