.NET Core override controller level Authorize attribute for a specific action

≯℡__Kan透↙ 提交于 2021-02-07 20:43:04

问题


Here is an example controller to explain the case

[Authorize]
public class AccountController : ControllerBase
{
    [AllowAnonymous]
    [Authorize(Policy = "SpecificPolicy")]
    public string MethodA() {}

    public string MethodB() {}
}
  • MethodA should only be authorized via "SpecificPolicy".
  • MethodB should be authorized via the Authorized attribute

The issue I'm having is that if I remove the AllowAnonymous attribute then Authorize on the controller takes precedence which I don't want for MethodA.

When I keep AllowAnonymous for MethodA then Authorize(Policy = "SpecificPolicy") is ignored.


回答1:


When I keep AllowAnonymous for MethodA then Authorize(Policy = "SpecificPolicy") is ignored.

[AllowAnonymous] bypasses all other authorization attributes. When you have it with other authorize attributes at the same time, all other attributes are ignored, even other attributes are the-more-specific method level.

For example:

[AllowAnonymous]
public class DashboardController : Controller
{
    [Authorize]
    public IActionResult Index()
    {
        return View();
    }
}

/dashboard will be open/public.

The issue I'm having is that if I remove the AllowAnonymous attribute then Authorize on the controller takes precedence which I don't want for MethodA.

When you have multiple authorize attributes, all of them need to be satisfied before you can make the call to the method. In your case, both [Authorize] and [Authorize(Policy = "SpecificPolicy")] must pass before access is granted.

If you don't want [Authorize] to take the precedence, you can only apply it to method B:

public class AccountController : ControllerBase
{
    [Authorize(Policy = "SpecificPolicy")]
    public string MethodA() {}

    [Authorize]
    public string MethodB() {}
}

I want to avoid putting specific [Authorize] attributes on actions since that Controller has lots of actions but a single action that has it's own authorize rule.

Then this might be good time for you to separate MethodA into Areas.

For example:

You still have [Authorize] on your AccountController, but just take out the MethodA:

[Authorize]
public class AccountController : ControllerBase
{
    public string MethodB() {}
}

Then you create an Area for MethodA:

[Area("specific")]
[Authorize(Policy = "SpecificPolicy")]
public abstract class SpecificControllerBase : ControllerBase
{ }

public class AccountController : SpecificationControllerBase
{
    public string MethodA() {}
}

Lastly you need to register the area route in your Startup.cs:

app.UseMvc(routes =>
{
    ...

    routes.MapRoute(
        name: "areaRoute",
        template: "{area:exists}/{controller=dashboard}/{action=index}/{id?}");

    routes.MapRoute(
        name: "default",
        template: "{controller=home}/{action=index}/{id?}");
});



回答2:


You could try to implement your own Authorize Attribute with checking the Policy.

Follow Steps below:

  • AllowAnonymousWithPolicyFilter

    public class AllowAnonymousWithPolicyFilter : IAsyncAuthorizationFilter
    {
    private readonly IAuthorizationService _authorization;
    public string Policy { get; private set; }
    
    public AllowAnonymousWithPolicyFilter(string policy, IAuthorizationService authorization)
    {
        Policy = policy;
        _authorization = authorization;
    }
    
    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        var authorized = await _authorization.AuthorizeAsync(context.HttpContext.User, Policy);
        if (!authorized.Succeeded)
        {
            context.Result = new ForbidResult();
            return;
        }
    }
    }
    
  • AllowAnonymousWithPolicyAttribute

    public class AllowAnonymousWithPolicyAttribute : TypeFilterAttribute, IAllowAnonymous
    {
    public AllowAnonymousWithPolicyAttribute(string Policy) : base(typeof(AllowAnonymousWithPolicyFilter))
    {
        Arguments = new object[] { Policy };
    }
    }
    
  • Use

    [Authorize]
     public class HomeController : Controller
    {
    [AllowAnonymousWithPolicy("MyPolicy")]
    public IActionResult About()
    {
        ViewData["Message"] = "Your application description page.";
    
        return View();
    }
    


来源:https://stackoverflow.com/questions/52729492/net-core-override-controller-level-authorize-attribute-for-a-specific-action

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!