将授权策略应用于整个控制器时忽略使用属性
Consume Attribute Ignored when Authorize Policy is applied to entire controller
我们一直在进行一些安全测试并发现一个问题,如果 posted 的内容类型不正确,则会返回 400 而不是 415。
现在只有当我将我的授权属性应用到整个控制器,然后在 post 操作上设置我的消耗属性时,才会发生这种情况。当 Authorize Attribute 与 Consumes Attribute 一起仅应用于一个动作时,这就可以正常工作了。
这个有效:Returns 415
public class MyController : Controller
{
[HttpPost]
[Authorize(Policy = "MyPolicy")]
[Consumes("application/x-www-form-urlencoded")]
public async Task<IActionResult> APostActrion(MyModel model)
{
return View();
}
}
这不是:Returns 400
[Authorize(Policy = "MyPolicy")]
public class MyController : Controller
{
[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public async Task<IActionResult> APostActrion(MyModel model)
{
return View();
}
}
编辑
这是我的政策示例
options.AddPolicy("MyPolicy", b =>
{
b.RequireAuthenticatedUser();
b.RequireClaim(ClaimTypes.Role, "MyRole");
b.Requirements.Add(new OrganisationRequirement());
});
这是 OrganisationRequirement
的 AuthorizationHandler
public class OrganisationHandler : AuthorizationHandler<OrganisationRequirement>
{
private readonly StatelessServiceContext _context;
public OrganisationHandler(StatelessServiceContext context)
{
_context = context;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, OrganisationRequirement requirement)
{
if (CanRequest(context))
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
return Task.CompletedTask;
}
private bool CanRequest(AuthorizationHandlerContext context)
{
string OrgId = Encoding.Unicode.GetString(_context.InitializationData, 0, _context.InitializationData.Length);
if (string.IsNullOrEmpty(OrgId))
{
return true;
}
if (context.User.HasClaim(c => c.Type == ClaimTypes.Role && (c.Value == RoleNames.SysAdmin)))
{
return true;
}
if (context.User.HasClaim(c => c.Type == ClaimTypes.Role && c.Value == RoleNames.Service)
&& context.User.HasClaim(c => (c.Type == CustomClaimTypes.OrgCode) && (c.Value == "system")))
{
return true;
}
if (context.User.HasClaim(c => (c.Type == CustomClaimTypes.OrgCode) && c.Value == OrgId))
{
return true;
}
return false;
}
}
事实证明,如果您有一个 [HTTPGet] 方法对应于您的 post 方法并且不使用 [HTTPGet] 对其进行注释,则 post 请求将定向到该获取操作.
这会导致问题:
public class MyController : Controller
{
[Authorize(Policy = "MyPolicy")]
public async Task<IActionResult> MyAction(int id)
{
return View();
}
[HttpPost]
[Authorize(Policy = "MyPolicy")]
[Consumes("application/x-www-form-urlencoded")]
public async Task<IActionResult> MyAction(MyModel model)
{
return View();
}
}
这解决了问题:
public class MyController : Controller
{
[HttpGet]
[Authorize(Policy = "MyPolicy")]
public async Task<IActionResult> MyAction(int id)
{
return View();
}
[HttpPost]
[Authorize(Policy = "MyPolicy")]
[Consumes("application/x-www-form-urlencoded")]
public async Task<IActionResult> MyAction(MyModel model)
{
return View();
}
}
我们一直在进行一些安全测试并发现一个问题,如果 posted 的内容类型不正确,则会返回 400 而不是 415。
现在只有当我将我的授权属性应用到整个控制器,然后在 post 操作上设置我的消耗属性时,才会发生这种情况。当 Authorize Attribute 与 Consumes Attribute 一起仅应用于一个动作时,这就可以正常工作了。
这个有效:Returns 415
public class MyController : Controller
{
[HttpPost]
[Authorize(Policy = "MyPolicy")]
[Consumes("application/x-www-form-urlencoded")]
public async Task<IActionResult> APostActrion(MyModel model)
{
return View();
}
}
这不是:Returns 400
[Authorize(Policy = "MyPolicy")]
public class MyController : Controller
{
[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public async Task<IActionResult> APostActrion(MyModel model)
{
return View();
}
}
编辑
这是我的政策示例
options.AddPolicy("MyPolicy", b =>
{
b.RequireAuthenticatedUser();
b.RequireClaim(ClaimTypes.Role, "MyRole");
b.Requirements.Add(new OrganisationRequirement());
});
这是 OrganisationRequirement
的 AuthorizationHandlerpublic class OrganisationHandler : AuthorizationHandler<OrganisationRequirement>
{
private readonly StatelessServiceContext _context;
public OrganisationHandler(StatelessServiceContext context)
{
_context = context;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, OrganisationRequirement requirement)
{
if (CanRequest(context))
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
return Task.CompletedTask;
}
private bool CanRequest(AuthorizationHandlerContext context)
{
string OrgId = Encoding.Unicode.GetString(_context.InitializationData, 0, _context.InitializationData.Length);
if (string.IsNullOrEmpty(OrgId))
{
return true;
}
if (context.User.HasClaim(c => c.Type == ClaimTypes.Role && (c.Value == RoleNames.SysAdmin)))
{
return true;
}
if (context.User.HasClaim(c => c.Type == ClaimTypes.Role && c.Value == RoleNames.Service)
&& context.User.HasClaim(c => (c.Type == CustomClaimTypes.OrgCode) && (c.Value == "system")))
{
return true;
}
if (context.User.HasClaim(c => (c.Type == CustomClaimTypes.OrgCode) && c.Value == OrgId))
{
return true;
}
return false;
}
}
事实证明,如果您有一个 [HTTPGet] 方法对应于您的 post 方法并且不使用 [HTTPGet] 对其进行注释,则 post 请求将定向到该获取操作.
这会导致问题:
public class MyController : Controller
{
[Authorize(Policy = "MyPolicy")]
public async Task<IActionResult> MyAction(int id)
{
return View();
}
[HttpPost]
[Authorize(Policy = "MyPolicy")]
[Consumes("application/x-www-form-urlencoded")]
public async Task<IActionResult> MyAction(MyModel model)
{
return View();
}
}
这解决了问题:
public class MyController : Controller
{
[HttpGet]
[Authorize(Policy = "MyPolicy")]
public async Task<IActionResult> MyAction(int id)
{
return View();
}
[HttpPost]
[Authorize(Policy = "MyPolicy")]
[Consumes("application/x-www-form-urlencoded")]
public async Task<IActionResult> MyAction(MyModel model)
{
return View();
}
}