How to handle authorization error after migrated from ASP.NET Core 2.1 to .NET 6?

902 views Asked by At

I have migrated my project from asp.net core 2.1 to .NET 6, and now I am facing an error with context.Resource as AuthorizationFilterContext which is return NULL.

I have implemented a custom Policy-based Authentication using AuthorizationFilterContext, It seems that.NET 6 do not support AuthorizationFilterContext Please help me how to modify the below code from asp.net core 2.1 to .NET6. thank you.

Here is the error message in this line var mvcContext = context.Resource as AuthorizationFilterContext;

mvcContext == NULL enter image description here

Here is the Implemention Code of AuthorizationHandler and AuthorizationHandlerContext

public class HasAccessRequirment : IAuthorizationRequirement { }
    public class HasAccessHandler : AuthorizationHandler<HasAccessRequirment>
    {
        public readonly HoshmandDBContext _context;
        public HasAccessHandler(HoshmandDBContext context)
        {
            _context = context;
        }
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasAccessRequirment requirement)
        {
            Contract.Ensures(Contract.Result<Task>() != null);
            List<int?> userGroupIds = new List<int?>();
            // receive the function informations

            var mvcContext = context.Resource as AuthorizationFilterContext;
            if ((mvcContext != null) && !context.User.Identity.IsAuthenticated)
            {
                mvcContext.Result = new RedirectToActionResult("UserLogin", "Logins", null);
                return Task.FromResult(Type.Missing);
            }
            if (!(mvcContext?.ActionDescriptor is ControllerActionDescriptor descriptor))
            {
                return Task.FromResult(Type.Missing);
            }
            var currntActionAddress = descriptor.ControllerName + "/" + descriptor.ActionName;
            // finding all information about controller and method from Tables 
            // check user has access to current action which is being called
            //allActionInfo = ListAcctionsFromDatabase;
            //bool isPostBack = allActionInfo.FirstOrDefault(a => a.action == currntActionAddress)?.IsMenu ?? true;
            bool isPostBack = false;
            if (!isPostBack)
            {
                mvcContext.Result = new RedirectToActionResult("AccessDenied", descriptor.ControllerName, null);
                context.Succeed(requirement);
                return Task.CompletedTask;
            }
            else
            {
                mvcContext.Result = new RedirectToActionResult("AccessDeniedView", descriptor.ControllerName, null);
                context.Succeed(requirement);
                return Task.CompletedTask;
            }

        }
    }

Here is my Program.cs Code:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("HasAccess", policy => policy.AddRequirements(new HasAccessRequirment()));
});

builder.Services.AddTransient<IAuthorizationHandler, HasAccessHandler>();

Here is the Controller Code:

   [Authorize(policy: "HasAccess")]
    public class HomeController : BaseController
    {
    }
1

There are 1 answers

4
Nathan On

There are some changes since .net core 3 about AuthorizationFilterContext:
A. MVC is no longer add AuthorizeFilter to ActionDescriptor and ResourceInvoker won’t call AuthorizeAsync().
B. It will add Filter as metadata to endpoint. Also, in .net 5 it changed the context.Resource as the type of DefaultHttpContext.

So here is the new method:

public class MyAuthorizationPolicyHandler : AuthorizationHandler<OperationAuthorizationRequirement>
{

    public MyAuthorizationPolicyHandler()
    {
    }

    protected async override Task HandleRequirementAsync(AuthorizationHandlerContext context, OperationAuthorizationRequirement requirement)
    {
        var result = false;

        if (context.Resource is Microsoft.AspNetCore.Http.DefaultHttpContext httpContext)
        {
            var endPoint = httpContext.GetEndpoint();
            if (endPoint != null)
            {
                var attributeClaims = endPoint.Metadata.OfType<MyAuthorizeAttribute>()
                //TODO: Add your logic here
            }

            if (result)
            {
                context.Succeed(requirement);
            }
        }
    }

Please refer to this discussion: "context.Resource as AuthorizationFilterContext" returning null in ASP.NET Core 3.0