Einfache Autorisierung in ASP.NET Core

Die Autorisierung in ASP.NET Core wird mit AuthorizeAttribute und den verschiedenen Parametern gesteuert. In der einfachsten Form wird durch das Anwenden des [Authorize]-Attributs auf einen Controller, eine Aktion oder eine Razor-Seite der Zugriff auf die authentifizierten Benutzer*innen dieser Komponente eingeschränkt.

Der folgende Code beschränkt den Zugriff auf den AccountController auf authentifizierte Benutzer*innen:

[Authorize]
public class AccountController : Controller
{
    public ActionResult Login()
    {
    }

    public ActionResult Logout()
    {
    }
}

Wenn die Autorisierung eine Aktion und nicht den Controller betreffen soll, wenden Sie das AuthorizeAttribute-Attribut auf die Aktion selbst an:

public class AccountController : Controller
{
   public ActionResult Login()
   {
   }

   [Authorize]
   public ActionResult Logout()
   {
   }
}

Jetzt können nur noch authentifizierte Benutzer*innen auf die Logout-Funktion zugreifen.

Sie können das AllowAnonymous-Attribut auch verwenden, um nicht authentifizierten Benutzer*innen den Zugriff auf einzelne Aktionen zu ermöglichen. Beispiel:

[Authorize]
public class AccountController : Controller
{
    [AllowAnonymous]
    public ActionResult Login()
    {
    }

    public ActionResult Logout()
    {
    }
}

Dadurch wird nur authentifizierten Benutzer*innen der Zugriff auf den AccountController erlaubt, mit Ausnahme der Aktion Login, die unabhängig vom Authentifizierungsstatus (auch anonym) für alle zugänglich ist.

Warnung

[AllowAnonymous] umgeht Autorisierungsanweisungen. Wenn Sie [AllowAnonymous] mit einem [Authorize]-Attribut kombinieren, werden die [Authorize]-Attribute ignoriert. Wenn Sie beispielsweise [AllowAnonymous] auf Controllerebene anwenden, gilt Folgendes:

  • Alle Autorisierungsanforderungen von [Authorize]-Attributen für denselben Controller oder Aktionsmethoden für den Controller werden ignoriert.
  • Authentifizierungsmiddleware wird nicht außer Kraft gesetzt, ist aber nicht unbedingt erfolgreich.

Der folgende Code beschränkt den Zugriff auf die LogoutModelRazor-Seite auf authentifizierte Benutzer*innen:

[Authorize]
public class LogoutModel : PageModel
{
    public async Task OnGetAsync()
    {

    }

    public async Task<IActionResult> OnPostAsync()
    {

    }
}

Informationen dazu, wie global die Authentifizierung aller Benutzer angefordert werden kann, finden Sie unter Authentifizierte Benutzer erforderlich.

Autorisieren von Attributen und Razor Pages

Das AuthorizeAttribute kann nicht auf Razor-Seitenhandler angewandt werden. Beispielsweise kann [Authorize] nicht auf OnGet, OnPost oder andere Seitenhandler angewandt werden. Ziehen Sie in Betracht, für Seiten mit unterschiedlichen Autorisierungsanforderungen für verschiedene Handler einen ASP.NET Core-MVC-Controller zu verwenden. Verwenden eines MVC-Controllers, wenn unterschiedliche Autorisierungsanforderungen bestehen:

  • Am wenigsten komplexer Ansatz
  • Der von Microsoft empfohlene Ansatz

Wenn Sie keinen MVC-Controller verwenden möchten, kann die Anwendung der Autorisierung auf Razor-Seitenhandlermethoden über die folgenden beiden Ansätze erfolgen:

  • Verwenden Sie separate Seiten für Seitenhandler mit unterschiedlichen Autorisierungsanforderungen. Verschieben Sie freigegebene Inhalte in Teilansichten. Diese Herangehensweise wird nach Möglichkeit empfohlen.

  • Schreiben Sie für Inhalte, die eine Seite gemeinsam nutzen müssen, einen Filter, der die Autorisierung im Rahmen von IAsyncPageFilter.OnPageHandlerSelectionAsync ausführt. Das GitHub-Projekt PageHandlerAuth veranschaulicht diesen Ansatz:

    [TypeFilter(typeof(AuthorizeIndexPageHandlerFilter))]
    public class IndexModel : PageModel
    {
        private readonly ILogger<IndexModel> _logger;
    
        public IndexModel(ILogger<IndexModel> logger)
        {
            _logger = logger;
        }
    
        public void OnGet()
        {
    
        }
    
        public void OnPost()
        {
    
        }
    
        [AuthorizePageHandler]
        public void OnPostAuthorized()
        {
    
        }
    }
    
    public class AuthorizeIndexPageHandlerFilter : IAsyncPageFilter, IOrderedFilter
    {
        private readonly IAuthorizationPolicyProvider policyProvider;
        private readonly IPolicyEvaluator policyEvaluator;
    
        public AuthorizeIndexPageHandlerFilter(
            IAuthorizationPolicyProvider policyProvider,
            IPolicyEvaluator policyEvaluator)
        {
            this.policyProvider = policyProvider;
            this.policyEvaluator = policyEvaluator;
        }
    
        // Run late in the selection pipeline
        public int Order => 10000;
    
        public Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) => next();
    
        public async Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
        {
            var attribute = context.HandlerMethod?.MethodInfo?.GetCustomAttribute<AuthorizePageHandlerAttribute>();
            if (attribute is null)
            {
                return;
            }
    
            var policy = await AuthorizationPolicy.CombineAsync(policyProvider, new[] { attribute });
            if (policy is null)
            {
                return;
            }
    
            await AuthorizeAsync(context, policy);
        }
    
        #region AuthZ - do not change
        private async Task AuthorizeAsync(ActionContext actionContext, AuthorizationPolicy policy)
        {
            var httpContext = actionContext.HttpContext;
            var authenticateResult = await policyEvaluator.AuthenticateAsync(policy, httpContext);
            var authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticateResult, httpContext, actionContext.ActionDescriptor);
            if (authorizeResult.Challenged)
            {
                if (policy.AuthenticationSchemes.Count > 0)
                {
                    foreach (var scheme in policy.AuthenticationSchemes)
                    {
                        await httpContext.ChallengeAsync(scheme);
                    }
                }
                else
                {
                    await httpContext.ChallengeAsync();
                }
    
                return;
            }
            else if (authorizeResult.Forbidden)
            {
                if (policy.AuthenticationSchemes.Count > 0)
                {
                    foreach (var scheme in policy.AuthenticationSchemes)
                    {
                        await httpContext.ForbidAsync(scheme);
                    }
                }
                else
                {
                    await httpContext.ForbidAsync();
                }
    
                return;
            }
        }
    

Warnung

Der beispielhafte Ansatz mit PageHandlerAuth bietet Folgendes nicht:

  • Erstellen mit auf die Seite, das Seitenmodell oder global angewandten Autorisierungsattributen. Das Erstellen von Autorisierungsattributen führt zu einer mehrfachen Ausführung von Authentifizierung und Autorisierung, wenn auch AuthorizeAttribute- oder AuthorizeFilter-Instanzen auf die Seite angewandt werden.
  • Zusammenarbeit mit dem restlichen Authentifizierungs- und Autorisierungssystem von ASP.NET Core. Sie müssen überprüfen, ob dieser Ansatz für Ihre Anwendung ordnungsgemäß funktioniert.

Eine Unterstützung von AuthorizeAttribute für Razor-Seitenhandler ist nicht geplant.