Nick
Nick

Reputation: 2907

Custom message in Response from IAuthorizationRequirement context failure

I have a custom requirement:

public sealed class MyRequirement : IAuthorizationRequirement
{
}

Which I register in my application:

.AddAuthorization(options =>
    options.AddPolicy(Policy.MyPolicy, policy => { policy.AddRequirements(new MyRequirement()); }))

And the handler for that has a few checks:

public sealed class MyHandler : AuthorizationHandler<MyRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyRequirement requirement)
    {
        if (!context.User.HasClaim(c => c.Type == CustomClaimTypes.Status))
        {
            //_logger.Warning($"Status missing");
            context.Fail();
        }
        else
        {
            var rawStatus = context.User.Claims.Single(x => x.Type == CustomClaimTypes.Status).Value;
            EnumExtensions.TryParseNullable<Status>(rawStatus, true, out var status);

            switch (status)
            {
                case null:
                    //_logger.Warning($"Authentication forbidden: Unexpected  status: {rawStatus}");
                    context.Fail();
                    break;
                case Status.A:
                case Status.B:
                    //_logger.Warning($"Authentication forbidden: Invalid status: {status}");
                    context.Fail();
                    break;
                case Status.C:
                    context.Succeed(requirement);
                    break;
            }
        }

        return Task.CompletedTask;
    }
}

This successfully returns 403 if the context fails but I want to add a custom message to the response such as the text that is in the logger.

I have been googling this and it looks almost impossible, which I do not understand since it feels like very basic functionality.

Any ideas how to add custom text to the reponse?

Upvotes: 4

Views: 692

Answers (1)

Nick
Nick

Reputation: 2907

Apologies for the delay in response.

I solved this by using this:

             switch (status)
            {
                case Status.A:
                {
                    context.Succeed(requirement);
                    break;
                }
                default:
                {
                    await SetForbiddenResultAsync(context.Resource);
                    context.Fail();
                    break;
                }
            }

where

    private async Task SetForbiddenResultAsync(object resource)
    {
         var forbiddenResult = new ForbiddenEntityResult(new Error(resource.name));
         mvcContext.Result = forbiddenResult;
         await mvcContext.Result.ExecuteResultAsync(mvcContext);
    }

where ForbiddenEntityResult is just a result type, you can replace it with any ObjectResult.

Here you can also do logging, or handle other results such as Unauthorized, etc

Upvotes: 1

Related Questions