web-dev-qa-db-fra.com

Azure Active Directory pour l'authentification et ASP.NET Core Identity pour l'autorisation

Je souhaite créer une application ASP.NET Core 2.0 utilisant Azure Active Directory comme fournisseur d'identité (pour l'authentification) mais Identité ASP.NET Core pour l'autorisation (par exemple, à l'aide d'attributs de contrôleur tels que '[Authorize (Roles = " Admin ")] '). Dans la solution, je m'attends à ce que la table de base de données d'identité locale AspNetUserLogins contienne des références aux identités Azure Active Directory

Je pense que la solution impliquerait transformation de la revendication pour décorer l'utilisateur authentifié avec les rôles extraits de ASP.NET Core Identity.

Mes problèmes:

  1. Je peux utiliser l'authentification Azure Active Directory à partir du modèle Visual Studio Solution, mais je ne vois pas comment ajouter et configurer ensuite ASP.NET Core Identity (par exemple, services.AddIdentity () etc. quelque part dans Startup.ConfigureServices ()).
  2. J'aimerais savoir où le crochet approprié consiste à transformer la revendication. (par exemple, OpenIdConnectEvents.OnTokenValidated ou peut-être une méthode AccountController)

Les étapes pour reproduire ma ligne de base ...

  1. Dans portal.Azure.com ...

    • Azure Active Directory> Enregistrements d'applications> Enregistrement d'une nouvelle application (vous pouvez le supprimer plus tard)
    • Attribuez un nom à l'application et définissez-la sur 'Wep app/API'
    • Définissez 'URL de connexion' sur quelque chose d'arbitraire du type 'https: // blabla'
    • Accédez à l'enregistrement de l'application nouvellement créé et copiez le 'ID de l'application'
  2. Créez un projet ASP.NET Core 2.0 à l'aide de Visual Studio 2017 15.4.2 ...

    • Application Web ASP.NET Core
    • .NET Framework, ASP.NET Core 2.0, 'Application Web'
    • Modifier l'authentification> 'comptes professionnels ou scolaires'
    • sélectionnez 'cloud - organisation unique'
    • entrez votre domaine 'quelque chose. onmicrosoft.com' (je suppose)
    • cliquez sur l'assistant pour créer le projet
    • modifiez appsettings.json et remplacez le 'ClientId' par le 'ID de l'application' (copié à partir de portal.Azure.com).
    • copier la valeur définie pour 'CallbackPath' (par exemple '/ signin-oidc')
    • accédez aux propriétés du projet> Débogage> et copiez l'URL IIS Express https (par exemple, 'https: // localhost: 44366 /').
    • revenez à la nouvelle inscription de l'application sur portal.Azure.com
    • 'URL de réponse'> Ajouter une nouvelle adresse de réponse à partir de la concaténation des deux informations ci-dessus (par exemple, 'https: // localhost: 44366/signin-oidc')
    • cliquez sur "Enregistrer"
    • Exécuter le projet dans Visual Studio
    • Connectez-vous à l'aide de votre compte Azure Active Directory (il vous sera demandé de consentir aux autorisations requises par l'application).
    • Vous devriez alors vous retrouver sur la page de démonstration d'ASP.NET Core

Je suis moins sûr d'ici ...

(J'ai emprunté du code à la solution générée par un modèle avec les "options d'authentification" définies sur "Comptes d'utilisateurs individuels"> "Stocker les comptes d'utilisateurs dans l'application".)

  • Ajouter un package de nuget Microsoft.AspNetCore.Identity.EntityFrameworkCore (j'ai dû mettre à niveau Microsoft.AspNetCore.Authentication.Cookies de 2.0.0 à 2.0.1 avant de l'installer)
  • Ajouter un package de pépites Microsoft.EntityFrameworkCore.SqlServer
  • Ajouter les classes suivantes

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext(DbContextOptions<AspNetCoreIdentity.Data.ApplicationDbContext> options) : base(options)
        {
        }
    
        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
        }
    }
    
    public class ApplicationUser : IdentityUser
    {
    }
    
  • Ajoutez ce qui suit au début de Startup.ConfigureServices ()

    services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
    
  • Ajouter une chaîne de connexion à appsettings.json (en supposant que l'instance SQL Server par défaut sur la base d'hôte locale et la base d'identité est nommée 'AspNetCoreIdentity')

    "ConnectionStrings": {
      "DefaultConnection": "Data Source=.\\;Initial Catalog=AspNetCoreIdentity;Integrated Security=True;MultipleActiveResultSets=True"
    }
    

Désormais, lorsque je lance à nouveau l'application, je me retrouve dans une boucle de redirection qui, à mon avis, s'exécute entre mon application et la connexion Azure Active Directory. Traçage montre ...

Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed for user: (null). Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker: Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.

J'ai ensuite essayé d'ajouter des méthodes à AccountController (Login, ExternalLogin) dans l'espoir de pouvoir atteindre un point d'arrêt, mais maintenant, je suis vraiment bloqué.

autres références...

10
jimalad

Je pense que cela fonctionne, mais je suis assez nouveau dans ce cadre, donc les critiques de cette méthode sont les bienvenues.

Au démarrage, je devais ajouter deux choses à l'exemple de Microsoft. 

  1. Définissez DefaultSignInScheme value sur AuthenticationProperties pour empêcher une exception Stackoverflow en cas d'échec de l'autorisation (voir ici ).
  2. Ajouter le chemin d'accès refusé au cookie de l'application

Startup.cs:

public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(sharedOptions =>
        {
            sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        })
        .AddAzureAd(options => Configuration.Bind("AzureAd", options))
        .AddCookie(options =>
        {
            options.AccessDeniedPath = "/AccessDenied";
        });
   // Remaining code removed

J'ai ensuite étendu le AzureAdAuthenticationBuilderExtensions > ConfigureAzureOptions class et j'effectue un travail supplémentaire (c'est-à-dire le chargement des rôles d'utilisateur à partir du magasin de rôles) lorsque l'événement de validation de jeton se produit.

AzureAdAuthenticationBuilderExtensions.cs

public void Configure(string name, OpenIdConnectOptions options)
        {
            options.ClientId = _azureOptions.ClientId;
            options.Authority = $"{_azureOptions.Instance}{_azureOptions.TenantId}";
            options.UseTokenLifetime = true;
            options.CallbackPath = _azureOptions.CallbackPath;
            options.RequireHttpsMetadata = false;

            options.Events = new OpenIdConnectEvents
            {                    
                OnTokenValidated = (context) =>
                {                           
                    // Load roles from role store here
                    var roles = new List<string>() { "Admin" };
                    var claims = new List<Claim>();
                    foreach (var role in roles) claims.Add(new Claim(ClaimTypes.Role, role));

                    var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
                    context.Principal.AddIdentity(claimsIdentity);

                    return Task.CompletedTask;       
                }                    
            };
        }
1
gwstroup