I'm using an authentication middleware that is making API requests to a third party service. This middleware then sets up the claims that are later handled by an AuthorizationHandler in conjunction with a IAuthorizationRequirement and a custom policy.
The middleware piece works and I'm able to build the claims:
context.User.AddIdentity(identity); // contains claims
Where I'm stuck is redirecting to a specific URL (there are custom rules for where we need to redirect) from the handler or attribute. From the handler I tried:
var mvcContext = context.Resource as Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext;
mvcContext.Result = new RedirectToActionResult("login", "home", null);
but it's ignored; only a 401 is returned. AuthorizeAttribute
no longer has OnAuthorization so I can't use that either...
Thoughts? Thanks.
Your approach with the AuthorizationFilterContext in the handler was almost correct. As described in this answer you need to also say context.Succeed(requirement);
for it to work.
So complete solution would be something like this:
Create a custom Requirement:
public class SomeCustomRequirement : IAuthorizationRequirement
{}
Create a custom Handler:
public class SomeCustomRequirementHandler : AuthorizationHandler<SomeCustomRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserInformationCompletedRequirement requirement)
{
if (!fulfillsRequirement())
if (context.Resource is AuthorizationFilterContext redirectContext)
redirectContext.Result = new RedirectResult("/Account/Unauthorized");
// even though this is weird it is necessary
context.Succeed(requirement);
}
}
}
Register the handler:
services.AddAuthorization(options =>
{
options.AddPolicy(IdentityConstants.UserInformationCompletePolicy, policy =>
{
policy.RequireAuthenticatedUser();
policy.Requirements.Add(new SomeCustomRequirement());
});
});
services.AddSingelton<IAuthorizationHandler, SomeCustomRequirementHandler>();
// OR transient if the handler uses the Entity Framework
services.AddTransient<IAuthorizationHandler, SomeCustomRequirementHandler>();
Even though my answer is late I hope it might help future visitors.
If the only thing you want to attempt in your API's Middleware is to perform a LogIn behaviour, as your code seems to explain, these possible cases are, in my opinion, thought-provoking :
If /login/home
redirects to a webpage:
HttpContext.Response.Redirect
to redirect to the LogIn webpage. As the documentation says, This would send a 301 code that any web browser can interpret. The HttpContext is available in the Invoke
method.If /login/home
redirects to a controller that performs logic that validates user identity:
Take also a look at Nate's post, and this question.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With