2021-10-15 11:27

讓 Net core 3.1 的 PageModel handler 可以用 AuthorizeAttribute

Razor Page 的 AuthorizeAttribute 只能用在 class 上,這樣就做不到細部的權限管控,為了讓 handler 也能用 AuthorizeAttribute 可以從 IPageFilter 進行處裡:

using System.Linq;
using System.Reflection;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace XXXXX.Api.Filters
{
    public class HandlerAuthorizeFilter : IPageFilter
    {
        /// <summary>在完成模型系結之後,于處理常式方法執行之前呼叫。</summary>
        public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
        {
            if(context.HandlerMethod == null) { return; }

            /* 取得 handler 上的 AuthorizeAttribute */
            var attr = context.HandlerMethod.MethodInfo
               .GetCustomAttribute<AuthorizeAttribute>();
            if (attr == null) { return; }

            /* 當前登入的使用者 */
            ClaimsPrincipal user = context.HttpContext.User;

            /* 檢查是否符合腳色權限 */
            bool isAuth = attr.Roles.Split(',').Any(user.IsInRole);

            /* 沒權限就給予 ForbidResult */
            if (!isAuth) { context.Result = new ForbidResult(); }
        }


        /// <summary>在選取處理常式方法之後,但在進行模型系結之前呼叫。</summary>
        public void OnPageHandlerSelected(PageHandlerSelectedContext context) { }


        /// <summary>在處理常式方法執行之後,在動作結果執行之前呼叫。</summary>
        public void OnPageHandlerExecuted(PageHandlerExecutedContext context) { }
    }
}

接著在 Startup.cs 進行過濾器配置:

public void ConfigureServices(IServiceCollection services)
{
    //...

    IMvcBuilder mvcBuilder = services
        .AddRazorPages(options =>
        {
            //...
        })
        .AddMvcOptions(options =>
        {
            //...
            options.Filters.Add(new HandlerAuthorizeFilter());
        })
        ;

    //...
}

然後在 PageModel 就可以用下面的方式撰寫:

public class IndexModel : PageModel
{
    [Authorize(Roles = "Admin")]
    public IActionResult OnGet()
    {
        return Page();
    }
}

0 回應: