43 votes

Comment puis-je configurer de multiples régimes d'auth ASP.NET Core 2.0?

Je suis en train de migrer mon auth trucs Core 2.0 et avoir un problème à l'aide de mon propre schéma d'authentification. Mon service d'installation de démarrage ressemble à ceci:

var authenticationBuilder = services.AddAuthentication(options =>
{
    options.AddScheme("myauth", builder =>
    {
        builder.HandlerType = typeof(CookieAuthenticationHandler);
    });
})
    .AddCookie();

Mon code de connexion dans le contrôleur ressemble à ceci:

var claims = new List<Claim>
{
    new Claim(ClaimTypes.Name, user.Name)
};

var props = new AuthenticationProperties
{
    IsPersistent = persistCookie,
    ExpiresUtc = DateTime.UtcNow.AddYears(1)
};

var id = new ClaimsIdentity(claims);
await HttpContext.SignInAsync("myauth", new ClaimsPrincipal(id), props);

Mais quand je suis dans un contrôleur ou d'une action de filtre, je n'ai qu'une seule identité, et il n'est pas authentifié un:

var identity = context.HttpContext.User.Identities.SingleOrDefault(x => x.AuthenticationType == "myauth");

La navigation de ces changements a été difficile, mais je suppose que je suis en train de faire .AddScheme mal. Toutes les suggestions?

EDIT: Voici (essentiellement) un propre app que les résultats non en deux sets de l'identité de l'Utilisateur.Identie:

namespace WebApplication1.Controllers
{
    public class Testy : Controller
    {
        public IActionResult Index()
        {
            var i = HttpContext.User.Identities;
            return Content("index");
        }

        public async Task<IActionResult> In1()
        {
            var claims = new List<Claim> { new Claim(ClaimTypes.Name, "In1 name") };
            var props = new AuthenticationProperties  { IsPersistent = true, ExpiresUtc = DateTime.UtcNow.AddYears(1) };
            var id = new ClaimsIdentity(claims);
            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(id), props);
            return Content("In1");
        }

        public async Task<IActionResult> In2()
        {
            var claims = new List<Claim> { new Claim(ClaimTypes.Name, "a2 name") };
            var props = new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTime.UtcNow.AddYears(1) };
            var id = new ClaimsIdentity(claims);
            await HttpContext.SignInAsync("a2", new ClaimsPrincipal(id), props);
            return Content("In2");
        }

        public async Task<IActionResult> Out1()
        {
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            return Content("Out1");
        }

        public async Task<IActionResult> Out2()
        {
            await HttpContext.SignOutAsync("a2");
            return Content("Out2");
        }
    }
}

Et De Démarrage:

namespace WebApplication1
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                })
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie("a2");

            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseAuthentication();

            app.UseMvc(routes =>
            {
                routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

62voto

barbara.post Points 110

Une autre possibilité consiste à déterminer lors de l'exécution d'authentification de la politique schéma de choisir, j'ai eu le cas où je pourrais avoir une authentification http porteur du jeton d'en-tête ou d'un cookie.

Ainsi, grâce à https://github.com/aspnet/Security/issues/1469

JWT jeton si un en-tête de la requête, puis OpenIdConnect (Azure AD) ou quoi que ce soit d'autre.

public void ConfigureServices(IServiceCollection services)
    {
        // Add CORS
        services.AddCors();

        // Add authentication before adding MVC
        // Add JWT and Azure AD (that uses OpenIdConnect) and cookies.
        // Use a smart policy scheme to choose the correct authentication scheme at runtime
        services
            .AddAuthentication(sharedOptions =>
            {
                sharedOptions.DefaultScheme = "smart";
                sharedOptions.DefaultChallengeScheme = "smart";
            })
            .AddPolicyScheme("smart", "Authorization Bearer or OIDC", options =>
            {
                options.ForwardDefaultSelector = context =>
                {
                    var authHeader = context.Request.Headers["Authorization"].FirstOrDefault();
                    if (authHeader?.StartsWith("Bearer ") == true)
                    {
                        return JwtBearerDefaults.AuthenticationScheme;
                    }
                    return OpenIdConnectDefaults.AuthenticationScheme;
                };
            })
            .AddJwtBearer(o =>
            {
                o.Authority = Configuration["JWT:Authentication:Authority"];
                o.Audience = Configuration["JWT:Authentication:ClientId"];
                o.SaveToken = true;
            })
            .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddAzureAd(options => Configuration.Bind("AzureAd", options));

        services
            .AddMvc(config =>
            {
                var policy = new AuthorizationPolicyBuilder()
                                 .RequireAuthenticatedUser()
                                 .Build();
                // Authentication is required by default
                config.Filters.Add(new AuthorizeFilter(policy));
                config.RespectBrowserAcceptHeader = true;
            });

            ...

            }

Edit de 07/2019: je dois ajouter un lien vers la proposition suivante, parce que c'est très utile aussi: vous ne pouvez pas utiliser les paramètres en AddAuthentication() comme je l'ai fait, parce que ce serait l'installation d'un schéma par défaut. Tout est bien expliqué ici: L'utilisation de plusieurs JWT Porteur d'Authentification J'aime vraiment cette autre apparoach!

43voto

Pinpoint Points 486

La navigation de ces changements a été difficile, mais je suppose que je suis en train de faire .AddScheme mal.

N'utilisez pas l' AddScheme: c'est un faible niveau de la méthode conçue pour les gestionnaires d'écrivains.

Comment puis-je configurer de multiples régimes d'auth ASP.NET Core 2.0?

Pour enregistrer le gestionnaire de cookies, il suffit de faire:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(options =>
        {
            options.DefaultScheme = "myauth1";
        })

       .AddCookie("myauth1");
       .AddCookie("myauth2");
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseAuthentication();

        // ...
    }
}

Il est important de noter que vous ne pouvez pas enregistrer plusieurs modes par défaut comme dans 1.x (le point de l'ensemble de cet immense refactoring est pour éviter d'avoir plusieurs authentification automatique middleware en même temps).

Si vous avez absolument besoin d'émuler ce comportement dans la version 2.0, vous pouvez écrire une coutume middleware manuellement des appels AuthenticateAsync() et crée un ClaimsPrincipal contenant toutes les identités dont vous avez besoin:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(options =>
        {
            options.DefaultScheme = "myauth1";
        })

       .AddCookie("myauth1");
       .AddCookie("myauth2");
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseAuthentication();

        app.Use(async (context, next) =>
        {
            var principal = new ClaimsPrincipal();

            var result1 = await context.AuthenticateAsync("myauth1");
            if (result1?.Principal != null)
            {
                principal.AddIdentities(result1.Principal.Identities);
            }

            var result2 = await context.AuthenticateAsync("myauth2");
            if (result2?.Principal != null)
            {
                principal.AddIdentities(result2.Principal.Identities);
            }

            context.User = principal;

            await next();
        });

        // ...
    }
}

6voto

https://stackoverflow.com/a/51897159/4425154's solution de l'aide. Quelques éléments à prendre en compte sur le dessus de la solution mentionnée,

  1. Assurez-vous que vous utilisez .net de base au moment de l'exécution 2.1 ou supérieur
  2. Assurez-vous d'une politique d'autorisation mentionnées ci-dessous si vous êtes à l'aide du middleware

       services.AddMvc(options =>
        {
            var defaultPolicy = new AuthorizationPolicyBuilder(new[] { CookieAuthenticationDefaults.AuthenticationScheme, JwtBearerDefaults.AuthenticationScheme, OpenIdConnectDefaults.AuthenticationScheme })
                      .RequireAuthenticatedUser()
                      .Build();
            options.Filters.Add(new AuthorizeFilter(defaultPolicy));
        })
    

2voto

Phong Nguyen Points 1

Dans le cas où quelqu'un a besoin de la solution, c'est ce que j'ai fait:

services.AddMvc(options =>
            {

var defaultPolicy = new AuthorizationPolicyBuilder()
    .AddAuthenticationSchemes(IdentityServerAuthenticationDefaults.AuthenticationScheme, BasicAuthenticationDefaults.AuthenticationScheme)
                .RequireAuthenticatedUser()
                .Build();

                options.Filters.Add(new AuthorizeFilter(defaultPolicy));
            });

services.AddAuthentication()
    .AddIdentityServerAuthentication(option config here)
    .AddBasicAuthentication(setting);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X