J'ai une application .NET Core 2.0 et j'ai un problème d'autorisation. Je souhaite utiliser une autorisation personnalisée avec des demandes spéciales. En-tête et authentification par défaut standard. Tout d'abord, j'ajoute une configuration dans Startup.cs:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    // ...
    services.AddAuthorization(options =>
    {
        options.AddPolicy(DefaultAuthorizedPolicy, policy =>
        {
            policy.Requirements.Add(new TokenAuthRequirement());
        });
    });
    services.AddSingleton<IAuthorizationHandler, AuthTokenPolicy>();
    // ...
}

AuthTokenPolicy.cs:

public class AuthTokenPolicy : AuthorizationHandler<TokenAuthRequirement>
{   
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TokenAuthRequirement requirement)
    {
        var filterContext = context.Resource as AuthorizationFilterContext;
        var response = filterContext.HttpContext.Response;
        try
        {
            // some validation code

            var isValidToken = isValidTokenTask.Result;
            if (!isValidToken)
            {
                response.StatusCode = 401;
                return Task.CompletedTask;
            }

            response.StatusCode = 200;
            context.Succeed(requirement);
        }
        catch (Exception)
        {
            return Task.CompletedTask;
        }
        return Task.CompletedTask;
    }
}

Et dans HomeController.cs:

[Authorize(Policy = Startup.DefaultAuthorizedPolicy)]
public async Task<IActionResult> IsVisible()

Si j'utilise le mauvais request.header dans AuthTokenPolicy, je le vois, mais dans les journaux, je vois cette erreur:

System.InvalidOperationException: Aucun authenticationScheme n'a été spécifié et aucun DefaultChallengeScheme n'a été trouvé. \ R \ n sur Microsoft.AspNetCore.Authentication.AuthenticationService.d__11.MoveNext () \ r \ n --- Fin de la trace de pile à partir de l'emplacement précédent où l'exception a été lancé --- \ r \ n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () \ r \ n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche de tâche) \ r \ n à Microsoft.AspNetCore.Mvc. ChallengeResult.d__14.MoveNext () \ r \ n --- Fin de la trace de pile à partir de l'emplacement précédent où l'exception a été levée --- \ r \ n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () \ r \ n à System .Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche de tâche) \ r \ n sur Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__19.MoveNext () \ r \ n --- Fin de la trace de pile à partir de l'emplacement précédent où l'exception a été levée --- \ r \ n à System.Runtime.ExceptionServices.ExceptionDispatchIn fo.Throw () \ r \ n sur System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche de tâche) \ r \ n sur Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__17.MoveNext () \ r \ n --- Trace de fin de pile à partir de l'emplacement précédent où l'exception a été levée --- \ r \ n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () \ r \ n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche de tâche) \ r \ n à Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__15.MoveNext () \ r \ n --- Fin de la trace de pile à partir de l'emplacement précédent où l'exception a été levée --- \ r \ n à System.Runtime.ExceptionServices. ExceptionDispatchInfo.Throw () \ r \ n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche de tâche) \ r \ n à Microsoft.AspNetCore.Builder.RouterMiddleware.d__4.MoveNext () \ r \ n --- Fin de trace de pile à partir de l'emplacement précédent où l'exception a été lancée --- \ r \ n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw ( ) \ r \ n sur System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche de tâche) \ r \ n sur Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.d__3.MoveNext () \ r \ n --- Fin de la trace de pile de la précédente emplacement où l'exception a été levée --- \ r \ n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () \ r \ n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche de tâche) \ r \ n à React.AspNet .BabelFileMiddleware.d__5.MoveNext () \ r \ n --- Fin de la trace de pile à partir de l'emplacement précédent où l'exception a été levée --- \ r \ n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () \ r \ n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche tâche) \ r \ n sur Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.d__6.MoveNext () \ r \ n --- Fin de la trace de la pile à partir de l'emplacement précédent où l'exception a été levée - - \ r \ n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () \ r \ n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche de tâche) \ r \ n à core.common.Middleware.LoggingMiddleware.d__3.MoveNext () dans D: \ Dev \ microservicePDP \ Template \ core.common \ Middleware \ LoggingMiddleware .cs: ​​ligne 72

Après avoir lu Migration de l'authentification et de l'identité vers ASP .NET Core 2.0 J'ai ajouté ce code dans startup.cs

Citation de l'article:

services.AddAuthentication(options => 
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
});

Définissez un schéma par défaut dans 2.0 si l'une des conditions suivantes est vraie: Vous souhaitez que l'utilisateur soit automatiquement connecté Vous utilisez l'attribut [Autoriser] ou les stratégies d'autorisation sans spécifier de schémas

J'ai ajouté AuthenticationScheme et DefaultChallengeScheme dans ConfigureServices(). Cela n'a pas aidé, la même erreur ici. J'ai essayé d'utiliser app.UseAuthentication(); dans la méthode Startup.Configure(), sans résultat.

Comment puis-je utiliser une autorisation personnalisée sans authentification?

42
Galina 16 nov. 2017 à 10:43

5 réponses

Meilleure réponse

Bien. La bonne réponse est: n'utilisez pas l'autorisation au lieu de l'authentification. Je devrais avoir un accès complet au service de tous les clients avec en-tête. Le code de travail est:

public class TokenAuthenticationHandler : AuthenticationHandler<TokenAuthenticationOptions> 
{
    public IServiceProvider ServiceProvider { get; set; }

    public TokenAuthenticationHandler (IOptionsMonitor<TokenAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IServiceProvider serviceProvider) 
        : base (options, logger, encoder, clock) 
    {
        ServiceProvider = serviceProvider;
    }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync () 
    {
        var headers = Request.Headers;
        var token = "X-Auth-Token".GetHeaderOrCookieValue (Request);

        if (string.IsNullOrEmpty (token)) {
            return Task.FromResult (AuthenticateResult.Fail ("Token is null"));
        }           

        bool isValidToken = false; // check token here

        if (!isValidToken) {
            return Task.FromResult (AuthenticateResult.Fail ($"Balancer not authorize token : for token={token}"));
        }

        var claims = new [] { new Claim ("token", token) };
        var identity = new ClaimsIdentity (claims, nameof (TokenAuthenticationHandler));
        var ticket = new AuthenticationTicket (new ClaimsPrincipal (identity), this.Scheme.Name);
        return Task.FromResult (AuthenticateResult.Success (ticket));
    }
}

Startup.cs:

#region Authentication
services.AddAuthentication (o => {
    o.DefaultScheme = SchemesNamesConst.TokenAuthenticationDefaultScheme;
})
.AddScheme<TokenAuthenticationOptions, TokenAuthenticationHandler> (SchemesNamesConst.TokenAuthenticationDefaultScheme, o => { });
#endregion

Et mycontroller.cs

[Authorize(AuthenticationSchemes = SchemesNamesConst.TokenAuthenticationDefaultScheme)]
public class MainController : BaseController
{ ... }

Je ne trouve pas TokenAuthenticationOptions maintenant, mais il était vide. J'ai trouvé la même classe PhoneNumberAuthenticationOptions:

public class PhoneNumberAuthenticationOptions : AuthenticationSchemeOptions
{
    public Regex PhoneMask { get; set; }// = new Regex("7\\d{10}");
}

Vous devez définir la classe statique SchemesNamesConst. Quelque chose comme:

public static class SchemesNamesConst
{
    public const string TokenAuthenticationDefaultScheme = "TokenAuthenticationScheme";
}
21
Massimiliano Kraus 1 mai 2020 à 14:10

Votre déclaration initiale dans la solution marquée n'est pas entièrement vraie. Bien que votre nouvelle solution puisse atteindre votre objectif initial, il est toujours possible de contourner l'erreur d'origine tout en préservant votre logique AuthorizationHandler - à condition que vous ayez des gestionnaires de schéma d'authentification de base en place, même s'il s'agit de squelettes fonctionnels.

De manière générale, les gestionnaires et les schémas d'authentification sont destinés à établir + valider l'identité, ce qui les rend nécessaires au fonctionnement des gestionnaires / stratégies d'autorisation - car ils fonctionnent sur la supposition qu'une identité a déjà été établie.

ASP.NET Dev Haok résume le mieux ici: "L'authentification aujourd'hui n'est pas du tout consciente de l'autorisation, elle ne se soucie que de produire un ClaimsPrincipal par schéma. L'autorisation doit être un peu consciente de l'authentification, donc AuthenticationSchemes dans la stratégie est un mécanisme pour que vous associez la stratégie aux schémas utilisés pour créer le principal de revendications effectif pour l'autorisation (ou il utilise simplement le httpContext.User par défaut pour la requête, qui repose sur DefaultAuthenticateScheme). " https://github.com/aspnet/Security/issues/1469

Dans mon cas, la solution sur laquelle je travaille fournissait son propre concept implicite d'identité, nous n'avions donc pas besoin de schémas / gestionnaires d'authentification - juste des jetons d'en-tête pour l'autorisation. Ainsi, jusqu'à ce que nos concepts d'identité changent, nos gestionnaires d'autorisation de jeton d'en-tête qui appliquent les stratégies peuvent être liés à des squelettes de schéma 1-à-1.

Balises sur les terminaux:

[Authorize(AuthenticationSchemes = "AuthenticatedUserSchemeName", Policy = "AuthorizedUserPolicyName")]

Startup.cs:

        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = "AuthenticatedUserSchemeName";
        }).AddScheme<ValidTokenAuthenticationSchemeOptions, ValidTokenAuthenticationHandler>("AuthenticatedUserSchemeName", _ => { });

        services.AddAuthorization(options =>
        {
            options.AddPolicy("AuthorizedUserPolicyName", policy =>
            {
                //policy.RequireClaim(ClaimTypes.Sid,"authToken");
                policy.AddAuthenticationSchemes("AuthenticatedUserSchemeName");
                policy.AddRequirements(new ValidTokenAuthorizationRequirement());
            });
            services.AddSingleton<IAuthorizationHandler, ValidTokenAuthorizationHandler>();

Le gestionnaire d'authentification vide et d'autorisation est appelé (similaire dans la configuration aux publications respectives d'OP) mais le gestionnaire d'autorisation applique toujours nos politiques d'autorisation.

2
Dagan Danevic 5 nov. 2018 à 06:27

Beaucoup de réponses ci-dessus sont correctes mais en même temps alambiquées avec d'autres aspects d'authN / authZ. Ce qui en fait résout l'exception en question est cette ligne:

services.AddScheme<YourAuthenticationOptions, YourAuthenticationHandler>(YourAuthenticationSchemeName, options =>
    {
        options.YourProperty = yourValue;
    })
-1
abatishchev 2 déc. 2019 à 18:43

Lorsque j'utilisais la politique avant de définir le schéma d'authentification par défaut. J'avais modifié le DefaultPolicy donc c'était légèrement différent. Cependant, la même chose devrait également fonctionner pour la politique d'ajout.

services.AddAuthorization(options =>
        {
            options.AddPolicy(DefaultAuthorizedPolicy, policy =>
            {
                policy.Requirements.Add(new TokenAuthRequirement());
                policy.AuthenticationSchemes = new List<string>()
                                {
                                    CookieAuthenticationDefaults.AuthenticationScheme
                                }
            });
        });

Tenez compte du fait que par défaut, la propriété AuthenticationSchemes utilise une liste en lecture seule. Je pense qu'il serait préférable de mettre en œuvre cela au lieu de List également.

4
Neville Nazerane 3 déc. 2017 à 19:11

Cela a fonctionné pour moi

// using Microsoft.AspNetCore.Authentication.Cookies;
// using Microsoft.AspNetCore.Http;

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
        options =>
        {
            options.LoginPath = new PathString("/auth/login");
            options.AccessDeniedPath = new PathString("/auth/denied");
        });
20
granadaCoder 18 mars 2020 à 17:11
47324129