Razor Pages - Trying to Implement Action Filter on Razor Page
Asked Answered
O

3

5

I want to write a custom filter which will check whether a user is logged in to my site, and redirect them back to the login page if they aren't.

I want the filter to apply automatically to the page when it loads.

I have tried the solution shown below, but the filter doesn't work at the moment.

Filter Code:

using Microsoft.AspNetCore.Mvc.Filters;

namespace MODS.Filters
{
    public class AuthorisationPageFilter : ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            System.Diagnostics.Debug.Write("Filter Executed");  //write to debugger to test if working

            //add real code here

            base.OnActionExecuted(context);
        }
    }
}

Next, here's the filter attribute applied to the page model:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using MODS.Filters;

namespace MODS.Pages.Menus
{
    [AuthorisationPageFilter]
    public class Admin_MainMenuModel : PageModel
    {
        public ActionResult Admin_MainMenu()
        {
            System.Diagnostics.Debug.Write("Function Executed");
            return new ViewResult();
        }
    }
}

I am under the impression that you need to call an action/method on the page for the function to apply when the page loads (please tell me if this is correct), so here is the code calling the Admin_MainMenu method in the .cshtml page file (in a code block at the top of the razor page):

Model.Admin_MainMenu();

My current thoughts are that either: 1. the filter itself is of the wrong type (could be IPageFilter instead?) 2. that the way I'm implementing it is wrong (either where I apply it to the page model, or when I call the method on the page).

Any help is greatly appreciated. Thanks.

Ovi answered 29/11, 2018 at 12:14 Comment(1)
Are you using Identity to manage authentication? If so, you can just put [Authorize] on your PageModel. If not, how are you authenticating users?Swollen
R
6

ActionFilterAttribute is for MVC (Controllers and Actions). For Razor Pages, you must use IPageFilter (IAsyncPageFilter for async implementation).

There are two different filter pipelines for MVC and Razor Pages

Razor Page filters IPageFilter and IAsyncPageFilter allow Razor Pages to run code before and after a Razor Page handler is run. Razor Page filters are similar to ASP.NET Core MVC action filters, except they can't be applied to individual page handler methods.

Filter methods for Razor Pages in ASP.NET Core

Racket answered 28/7, 2020 at 9:59 Comment(0)
R
5

It's just as simple as the ActionFilterAttribute. All you need is to create an Attribute derived class that implements either IPageFilter or IAsyncPageFilter (Both would also work).

[AttributeUsage(AttributeTargets.Class)]
public class CustomPageFilterAttribute : Attribute, IAsyncPageFilter
{
    // Executes first
    public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
    {
        // TODO: implement this
    }

    // Executes last
    public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next)
    {
        // Before action execution

        await next();

        // After action execution
    }
}

Now, you can use your attribute in your PageModel.

[CustomPageFilter]
public class IndexModel : PageModel
{
    public void OnGet() { }
}
Raeleneraf answered 5/12, 2021 at 21:17 Comment(0)
N
0

This answer is for AspNet MVC rather than AspNetCore MVC, but may be useful to someone:

If it's for Authorization, I would use the AuthorizeAttribute class.

Something like this:

using System.Web.Mvc;

namespace MODS.Filters
{
    public class CustomAuthorizeUserAttribute : AuthorizeAttribute
    {
        // Custom property, such as Admin|User|Anon
        public string AccessLevel { get; set; }

        // Check to see it the user is authorized
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            System.Diagnostics.Debug.Write("Authorize Executed");  //write to debugger to test if working

            // Use Core MVC Security Model
            var isAuthorized = base.AuthorizeCore(httpContext);
            if (!isAuthorized)
            {
                return false;
            }

            // Or use your own method of checking that the user is logged in and authorized. Returns a Boolean value.
            return MySecurityHelper.CheckAccessLevel(AccessLevel);
        }

        // What to do when not authorized
        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            filterContext.Result = new RedirectToRouteResult(
                    new RouteValueDictionary(
                        new
                        {
                            controller = "Error",
                            action = "NotFound"
                        })
                    );
        }
    }
}

Then Decorate the Controller or Action with the CustomAuthorizeUser Attribute:

using MODS.Filters;

namespace MODS.Pages.Menus
{
    [CustomAuthorizeUser(AccessLevel = "Admin")]
    public class Admin_MainMenuModel : PageModel
    {
        public ActionResult Admin_MainMenu()
        {
            System.Diagnostics.Debug.Write("Function Executed");
            return new ViewResult();
        }
    }
}

Hope this helps!

Neodarwinism answered 29/11, 2018 at 13:23 Comment(3)
Thanks for your answer. Unfortunately, it seems that the : AuthorizeAttribute class is only available in ASP.NET MVC, and not ASP.NET Core, which is what I'm using. My main issue here is how to implement an : ActionFilterAttribute (or some more suitable .NET core equivalent) so that the filter is used every time the page is done loading.Ovi
Ok, I didn't realise that. I found this question, which has some good answers that may help: #31464859Neodarwinism
Thanks, I think that post will be useful. As a side question, I was wondering if a filter is really the best way to do this kind of redirection. I'm quite new to ASP.NET, and was wondering if you (or indeed anyone) else had an opinion on this matter.Ovi

© 2022 - 2024 — McMap. All rights reserved.