Autenticação de Cliente MVC Interno com OIDC e IdentityServer4

  1. Visão Geral da Solução

Este guia detalha a implementação de um sistema de Single Sign-On (SSO) para aplicações MVC internas, utilizando o IdentityServer4 como provedor de identidade e o protocolo OpenID Connect (OIDC). O objetivo é permitir que clientes MVC autentiquem usuários através de uma página de login centralizada, empregendo o fluxo de concessão implícita (Implicit Grant) do OAuth2.

Para simplificar a integração, a autenticação do cliente MVC será gerenciada por cookies, e faremos uso direto dos serviços de identidade OIDC embutidos no IdentityServer4.

  1. Conceitos Chave

  • IdentityResource: Define recursos de identidade conforme especificado pelo protocolo OIDC. Esses recursos possuem um nome exclusivo e contêm declarações (claims) sobre o usuário que são incluídas no token de identidade após a autenticação. Exemplos comuns incluem OpenId (necessário para OIDC) e Profile (para informações básicas do perfil do usuário).
  • IIdentityServerInteractionService: Uma interface fornecida pelo IdentityServer4 que facilita a interação com o servidor de identidade, como o redirecionamento para a página de login ou o processamento de respostas de consentimento. Embora útil para cenários mais complexos, para a configuração básica de cliente MVC com OIDC, seu uso pode ser implícito ou minimizado.
  1. Configuração do Cliente Web MVC

Para começar, crie um novo projeto de aplicação web MVC. Para este exemplo, o cliente MVC será configurado para rodar no endereço http://localhost:5030.

3.1. Adição de Pacotes NuGet Essenciais

Adicione o seguinte pacote ao seu projeto MVC. Este pacote fornece o middleware necessário para integrar o OpenID Connect com ASP.NET Core:

 <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="3.1.0" />

Nota: A versão do pacote deve ser compatível com a versão do seu ASP.NET Core. A versão 3.1.0 é um exemplo para IdentityServer4 v4.x.x.

3.2. Registro do Serviço OIDC e Ativação do Middleware de Autenticação

No arquivo Startup.cs do seu projeto MVC, configure os serviços de autenticação e o middleware:

// Método ConfigureServices: Registra os serviços de autenticação
public void ConfigureServices(IServiceCollection servicos)
{
    servicos.AddControllersWithViews();

    servicos.AddAuthentication(configAutenticacao =>
    {
        configAutenticacao.DefaultScheme = "Cookies"; // Define o esquema padrão para armazenamento de sessão
        configAutenticacao.DefaultChallengeScheme = "oidc"; // Define o esquema para iniciar o desafio OIDC
    })
    .AddCookie("Cookies", opcoesCookie =>
    {
        // Configurações adicionais para o cookie de autenticação, se necessário
        opcoesCookie.Cookie.Name = "AplicacaoMvcSso";
        opcoesCookie.ExpireTimeSpan = TimeSpan.FromMinutes(30);
        opcoesCookie.SlidingExpiration = true;
    })
    .AddOpenIdConnect("oidc", opcoesOidc =>
    {
        opcoesOidc.SignInScheme = "Cookies"; // Esquema a ser usado para persistir a identidade após o login OIDC
        opcoesOidc.Authority = "http://localhost:5010"; // URL base do IdentityServer
        opcoesOidc.RequireHttpsMetadata = false; // Desabilitado para ambiente de desenvolvimento HTTP
        opcoesOidc.ClientId = "cliente_mvc_app"; // ID do cliente registrado no IdentityServer
        opcoesOidc.SaveTokens = true; // Salva os tokens recebidos (access_token, id_token, refresh_token)
        opcoesOidc.GetClaimsFromUserInfoEndpoint = true; // Opcional: Busca claims adicionais do UserInfo Endpoint
    });
}

// Método Configure: Ativa o middleware de autenticação
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ... outros middlewares

    app.UseRouting();

    app.UseAuthentication(); // Deve vir antes do UseAuthorization
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

Para proteger as páginas do cliente MVC, use o atributo [Authorize]. Ao tentar acessar uma página protegida, o usuário será automaticamente redirecionado para a página de login do IdentityServer.

[Authorize]
public class HomeController : Controller
{
    // ... métodos do controlador
}

  1. Configuração do Lado do Servidor (IdentityServer4)

No projeto do IdentityServer, é necessário definir os recursos de identidade (IdentityResource) e registrar o cliente MVC.

4.1. Adição de Recursos de Identidade e Definição do Cliente

No arquivo de configuração do IdentityServer (ex: Config.cs), adicione os recursos de identidade e o cliente:

using IdentityServer4.Models;
using IdentityServer4;
using System.Collections.Generic;

public static class Configuracao
{
    // Define os recursos de identidade disponíveis
    public static IEnumerable<IdentityResource> ObterRecursosIdentidade()
    {
        return new List<IdentityResource>
        {
            new IdentityResources.OpenId(), // Recurso obrigatório para OIDC
            new IdentityResources.Profile()  // Inclui claims como nome, sobrenome, etc.
        };
    }

    // Define os clientes que podem se conectar ao IdentityServer
    public static IEnumerable<Client> ObterClientes()
    {
        return new List<Client>
        {
            new Client
            {
                ClientId = "cliente_mvc_app", // ID do cliente, deve corresponder ao configurado no MVC
                ClientName = "Aplicação MVC Interna",
                RequireConsent = false, // Desabilita a tela de consentimento para este cliente
                AllowedGrantTypes = GrantTypes.Implicit, // Fluxo de concessão implícita
                RedirectUris = { "http://localhost:5030/signin-oidc" }, // URI de retorno após o login bem-sucedido
                PostLogoutRedirectUris = { "http://localhost:5030/signout-callback-oidc" }, // URI de retorno após o logout
                AllowedScopes = new List<string> // Escopos que o cliente pode solicitar
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile
                }
            }
        };
    }

    // Outros métodos para ApiResources, ApiScopes, TestUsers, etc.
}

No método ConfigureServices do Startup.cs do IdentityServer, certifique-se de registrar esses recursos:

public void ConfigureServices(IServiceCollection servicos)
{
    servicos.AddIdentityServer()
        .AddDeveloperSigningCredential() // Apenas para desenvolvimento; use certificado em produção
        // .AddInMemoryApiResources(Configuracao.ObterRecursosApi()) // Se houver ApiResources
        .AddInMemoryIdentityResources(Configuracao.ObterRecursosIdentidade())
        .AddInMemoryClients(Configuracao.ObterClientes())
        // .AddInMemoryApiScopes(Configuracao.ObterEscoposApi()) // Para IdentityServer4 v3.1+
        .AddTestUsers(Configuracao.ObterUsuariosTeste()); // Usuários para teste em memória
}

  1. Verificação da Autenticação

Para testar a configuração, inicie o projeto do IdentityServer (normalmente em http://localhost:5010) e, em seguida, o projeto do cliente MVC (http://localhost:5030). Ao acessar a página inicial do cliente MVC (se ela estiver protegida com [Authorize]), você será automaticamente redirecionado para a página de login do IdentityServer.

Insira as credenciais de um usuário configurado no Configuracao.ObterUsuariosTeste() do IdentityServer.

5.1. Implementação do Método de Login (Exemplo do IdentityServer)

No controlador de conta do IdentityServer (ex: AccountController.cs), o método de login deve processar as credenciais e autenticar o usuário:

[HttpPost]
public async Task<IActionResult> Entrar(DadosLoginViewModel credenciais, string urlRedirecionamento)
{
    ViewData["UrlRetorno"] = urlRedirecionamento;

    // Assumindo que _servicoUsuarios é um serviço que gerencia os usuários de teste
    var usuarioEncontrado = _servicoUsuarios.BuscarPorNomeUsuario(credenciais.NomeUsuario);

    if (usuarioEncontrado == null)
    {
        ModelState.AddModelError(nameof(credenciais.NomeUsuario), "Usuário não existe.");
        return View(credenciais);
    }

    if (_servicoUsuarios.ValidarCredenciais(credenciais.NomeUsuario, credenciais.Senha))
    {
        var propriedadesAutenticacao = new AuthenticationProperties
        {
            IsPersistent = true, // Mantém a sessão do usuário persistente
            ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(30)) // Expira em 30 minutos
        };

        var usuarioIdentity = new IdentityServerUser(usuarioEncontrado.SubjectId)
        {
            DisplayName = usuarioEncontrado.Username
        };

        // Realiza o login do usuário no contexto HTTP
        await HttpContext.SignInAsync(usuarioIdentity, propriedadesAutenticacao);

        // Redireciona para a URL original após o login
        return Redirect(urlRedirecionamento);
    }

    ModelState.AddModelError(string.Empty, "Credenciais inválidas.");
    return View(credenciais);
}

Tags: IdentityServer4 OpenIDConnect OIDC ASPNETCore MVC

Publicado em 6-4 00:05 por Thomas