可以禁用组时的扩展授权
Extended authorization when group can be disabled
我正在编写 .net core 3.1 API 应用程序并在应用程序中实现了授权。它是通过 IPolicyRequirement 和 AuthorizationHandler 完成的。
services.AddAuthorizationCore(options =>
{
AddPolicy(options, new UserRequirement());
});
services.AddTransient<IAuthorizationHandler, UserHandler>();
并且需要的控制器用 Authorize
属性修饰。
[ApiController]
[Authorize(Policy = UserRequirement.Policy)]
[Route("/api/[controller]")]
public class TeamDetailsController : ControllerBase
{
...
}
一切正常,并在指定的地方限制对控制器调用的访问。
现在我需要根据是否启用帐户所属的团队来限制访问。因此,如果团队被禁用,人们可以登录,但无法访问大多数端点。
他们仍然应该能够访问一些端点,否则他们将无法执行业务指定的操作,以允许重新启用团队。不允许任何角色调用该端点 - 仅由授权策略指定。
我也可以通过政策要求做到这一点,但现在我想要一个带有 403 的特定错误消息,因此,API 调用者可以将基于角色的 403 与团队禁用的 403 区分开来。我认为 403对于这两种情况都是理想的代码,因为在这两种情况下都禁止访问指定的端点,在某些情况下只是出于与角色无关的原因。
所以,总而言之,我需要 return 403 带有政策要求的消息,例如:
public class UserHandler : AuthorizationHandler<UserRequirement>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
UserRequirement requirement)
{
var authenticatedUser = GetUserFromClaims();
if (!await TeamIsEnabled(authenticatedUser))
{
context.Resource.Result = new JsonResult("Custom message");
return;
}
if (!await RoleIsAllowed())
return;
context.Succeed(requirement);
}
}
上面的代码不起作用,因为 content.Resource 是 RouteEndpoint
类型并且没有要发送的结果 属性。
我的问题是:
- 我的方法使用策略要求来禁用基于授权策略要求的资源访问是否符合行业标准?
- 如果是这样,我如何 return 为团队禁用 403 发送消息?
- 如果 403 不应该在团队被禁用时 returned,它应该是什么代码?我不想 return 409 冲突,因为它用于数据库并发异常。
我应该使用中间件和 IAsyncResultFilter 吗?我可以使用它,但我想我应该问问社区我是否可以逃脱
谢谢。
所以,最后我将它们分成 2 位:
- 实现 IAsyncAuthorizationFilter 以处理组 on/off、returns 400 的过滤器,其中包含错误详细信息,因为我无法将过滤器设置为带有消息的 return 403。
- 实现 AuthorizationHandler 以限制对特定用户的访问和要求实现 IPolicyRequirement 的处理程序。
在 startup.cs
中我们有:
services.AddControllers(opt =>
{
...
opt.Filters.Add<GroupIsEnabledFilter>();
...
});
services.AddAuthorizationCore(options =>
{
AddPolicy(options, new MaintainerRequirement());
AddPolicy(options, new SuperUserRequirement());
})
...
;
services.AddTransient<IAuthorizationHandler, MaintainerHandler>();
services.AddTransient<IAuthorizationHandler, SuperUserHandler>();
过滤器模板可以是这样的:
public class GroupIsEnabledFilter : IAsyncAuthorizationFilter
{
public GroupIsEnabledFilter(...)
{
...
//inject your dependencies here
...
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (AllowsDisabledGroup(context)) //use context.ActionDescriptor.EndpointMetadata to get endpoint details
return;
var group = _authService.GetGroupId();
if (await GroupIsActive(group))
return;
var problemDetails = new ProblemDetails
{
...
};
context.Result = new ObjectResult(problemDetails)
{
ContentTypes = new MediaTypeCollection { new MediaTypeHeaderValue("application/json") },
StatusCode = StatusCodes.Status400BadRequest
};
}
}
我正在编写 .net core 3.1 API 应用程序并在应用程序中实现了授权。它是通过 IPolicyRequirement 和 AuthorizationHandler 完成的。
services.AddAuthorizationCore(options =>
{
AddPolicy(options, new UserRequirement());
});
services.AddTransient<IAuthorizationHandler, UserHandler>();
并且需要的控制器用 Authorize
属性修饰。
[ApiController]
[Authorize(Policy = UserRequirement.Policy)]
[Route("/api/[controller]")]
public class TeamDetailsController : ControllerBase
{
...
}
一切正常,并在指定的地方限制对控制器调用的访问。
现在我需要根据是否启用帐户所属的团队来限制访问。因此,如果团队被禁用,人们可以登录,但无法访问大多数端点。
他们仍然应该能够访问一些端点,否则他们将无法执行业务指定的操作,以允许重新启用团队。不允许任何角色调用该端点 - 仅由授权策略指定。
我也可以通过政策要求做到这一点,但现在我想要一个带有 403 的特定错误消息,因此,API 调用者可以将基于角色的 403 与团队禁用的 403 区分开来。我认为 403对于这两种情况都是理想的代码,因为在这两种情况下都禁止访问指定的端点,在某些情况下只是出于与角色无关的原因。
所以,总而言之,我需要 return 403 带有政策要求的消息,例如:
public class UserHandler : AuthorizationHandler<UserRequirement>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
UserRequirement requirement)
{
var authenticatedUser = GetUserFromClaims();
if (!await TeamIsEnabled(authenticatedUser))
{
context.Resource.Result = new JsonResult("Custom message");
return;
}
if (!await RoleIsAllowed())
return;
context.Succeed(requirement);
}
}
上面的代码不起作用,因为 content.Resource 是 RouteEndpoint
类型并且没有要发送的结果 属性。
我的问题是:
- 我的方法使用策略要求来禁用基于授权策略要求的资源访问是否符合行业标准?
- 如果是这样,我如何 return 为团队禁用 403 发送消息?
- 如果 403 不应该在团队被禁用时 returned,它应该是什么代码?我不想 return 409 冲突,因为它用于数据库并发异常。
我应该使用中间件和 IAsyncResultFilter 吗?我可以使用它,但我想我应该问问社区我是否可以逃脱
谢谢。
所以,最后我将它们分成 2 位:
- 实现 IAsyncAuthorizationFilter 以处理组 on/off、returns 400 的过滤器,其中包含错误详细信息,因为我无法将过滤器设置为带有消息的 return 403。
- 实现 AuthorizationHandler 以限制对特定用户的访问和要求实现 IPolicyRequirement 的处理程序。
在 startup.cs
中我们有:
services.AddControllers(opt =>
{
...
opt.Filters.Add<GroupIsEnabledFilter>();
...
});
services.AddAuthorizationCore(options =>
{
AddPolicy(options, new MaintainerRequirement());
AddPolicy(options, new SuperUserRequirement());
})
...
;
services.AddTransient<IAuthorizationHandler, MaintainerHandler>();
services.AddTransient<IAuthorizationHandler, SuperUserHandler>();
过滤器模板可以是这样的:
public class GroupIsEnabledFilter : IAsyncAuthorizationFilter
{
public GroupIsEnabledFilter(...)
{
...
//inject your dependencies here
...
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (AllowsDisabledGroup(context)) //use context.ActionDescriptor.EndpointMetadata to get endpoint details
return;
var group = _authService.GetGroupId();
if (await GroupIsActive(group))
return;
var problemDetails = new ProblemDetails
{
...
};
context.Result = new ObjectResult(problemDetails)
{
ContentTypes = new MediaTypeCollection { new MediaTypeHeaderValue("application/json") },
StatusCode = StatusCodes.Status400BadRequest
};
}
}