问题
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