10
votes

Autorisation dans les pages ASP .NET Core Razor

Je ne parviens pas à implémenter l'autorisation basée sur des stratégies dans ASP .NET Core pour une action sur une page de rasoir.

J'ai lu ce document complet sur l'autorisation et j'ai utilisé ses exemples à titre indicatif.

Code d'action de la page Razor:

GET /Account?handler=Create

Code dans la configuration du service:

_ = services.AddAuthorization(options => {
    options.AddPolicy("test", policy =>
        policy.RequireAssertion(context =>
            false));
});

Je m'attends à ce que si j'appelle l'action ou le service de point final, par exemple

[Authorize(Policy = "test")]
public async Task<IActionResult> OnGetCreateAsync(string id)

alors la demande sera refusée avec une réponse d'état 403 parce que la politique de «test» indique que tout le monde n'est pas autorisé. Cependant, dans la pratique réelle, l'action est appelée avec succès.


5 commentaires

Pouvez-vous montrer votre méthode Configure au démarrage?


Vous devez également utiliser le middleware UseAuthentication() pour que ces stratégies d'autorisation soient réellement importantes.


Avez-vous ajouté le middleware UseAuthentication ()


Oui. J'ai ajouté un middleware d'authentification.


Document mis à jour sur github.com/dotnet/AspNetCore.Docs/pull/18949/files


3 Réponses :


8
votes

Razor Pages ne prend actuellement pas en charge [Authorize] au niveau du gestionnaire . c'est-à-dire que vous ne pouvez autoriser qu'une page dans son ensemble , sur le PageModel lui-même, comme indiqué dans la documentation :

Les stratégies ne peuvent pas être appliquées au niveau du gestionnaire de page Razor, elles doivent être appliquées à la page.

Si l'autorisation de la page dans son ensemble n'est pas une solution viable, vous devrez peut-être déplacer votre gestionnaire OnGetCreateAsync dans une paire contrôleur / action, qui peut être attribuée avec [Authorize] conséquence.

Il existe également un problème lié à GitHub dans la documentation à ce sujet:

L'attribut de filtre [Authorize] est pris en charge depuis la version 2.0 dans Razor Pages, mais notez qu'il fonctionne au niveau de la classe de modèle de page

Si vous avez besoin d'une meilleure solution de contournement, consultez la réponse d'akbar et la réponse de Jim Yabro .


0 commentaires

2
votes

Une autre solution consiste à vérifier l'authentification par la clause if.

var user = await _userManager.FindByEmailAsync(model.Email);
var roles = await _userManager.GetRolesAsync(user);

et vous pouvez également vérifier les roles en trouvant le rôle:

if (!HttpContext.User.Identity.IsAuthenticated)
    {
      return Redirect("/Front/Index");
    }


0 commentaires

0
votes

Puisque la question n'indiquait pas que l' AuthorizeAttribute est absolument une exigence de mise en œuvre, je présenterai une alternative à la documentation.

Une fois que vous avez configuré vos stratégies dans Startup.cs , vous pourrez vérifier ces stratégies à partir des gestionnaires de page.

  1. Injectez IAuthorizationService dans votre constructeur de modèle de page
  2. Appelez AuthorizeAsync() depuis le gestionnaire.
  3. Exécutez une vérification conditionnelle sur la propriété .Succeeded du résultat.
  4. Si .Succeeded est false, renvoie un résultat Forbid() .

Cela a presque le même résultat que [Authorize(Policy=...)] mais s'exécute plus tard dans le cycle de vie de la page. Soyez conscient de cela au cas où votre politique d'autorisation essaie de faire des choses complexes. Pour la majorité des cas d'utilisation auxquels je pense en ce moment, cette solution est satisfaisante.

@if (await AuthorizationService.PassesTest(User)) {
    <span>You passed the test!</span>
}

Au-delà de la portée de la question, il y a quelques autres notes à prendre en compte.

Tout d'abord, sachez que vous pouvez accéder à ce même service à partir des vues. Vous devrez vous assurer que l'instruction using est présente soit dans la page elle-même, soit dans votre _ViewImports.cshtml .

public static class PassesTestExtension {
    public static async Task<bool> PassesTest(this IAuthorizationService authorizationService, ClaimsPrincipal user) {
        var check = await authorizationService.AuthorizeAsync(user, "test");
        return check.Succeeded;
    }
}

Si vous n'aimez pas son apparence, vous pouvez soit intégrer votre appel attendu dans la vérification conditionnelle et enchaîner le .Succeeded directement, soit déclarer votre test comme une méthode d'extension afin que votre vérification soit un peu plus lisible .

@page
@model App.Pages.TestPageModel
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

@{
    var test = await AuthorizationService.AuthorizeAsync(User, "test");
}

@if (test.Succeeded) {
    <span>You passed the test!</span>
}

Votre vérification conditionnelle ressemblera maintenant à ceci:

using Microsoft.AspNetCore.Authorization;
// ...

public class TestPageModel : PageModel {
    readonly IAuthorizationService AuthorizationService;

    public TestPageModel(IAuthorizationService authorizationService) {
        AuthorizationService= authorizationService;
    }

    // Everyone can see this handler.
    public void OnGet() { }

    // Everyone can access this handler, but will be rejected after the check.
    public async Task<IActionResult> OnPostAsync() {
        
        // This is your policy you've defined in Startup.cs
        var policyCheck = await AuthorizationService.AuthorizeAsync(User, "test");

        // Check the result, and return a forbid result to the user if failed.
        if (!policyCheck.Succeeded) {
            return Forbid();
        }

        // ...

        return Page(); // Or RedirectToPage etc
    }
}

Un autre avantage de la méthode d'extension en plus de la lisibilité est que vous pouvez la modifier rapidement pour retourner !check.Succeeded plutôt !check.Succeeded à voir votre vue entière comme si vous n'étiez pas dans ce rôle à des fins de test.


0 commentaires