很容易
的 需求 强>
public class PrivateProfileRequirement : IAuthorizationRequirement { public string ClaimType { get; } public PrivateProfileRequirement(string claimType) { ClaimType = claimType; } } public class PrivateProfileHandler : AuthorizationHandler<PrivateProfileRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PrivateProfileRequirement requirement) { if (context.User != null) { if (context.User.Claims.Any(c => string.Equals(c.Type, requirement.ClaimType, StringComparison.OrdinalIgnoreCase))) { if (context.User.Identities.Any(i => string.Equals(i.GetId(), context.Resource))) { context.Succeed(requirement); } } } return Task.CompletedTask; } }
的 Startup.cs 强>
services.AddAuthorization(options => { options.AddPolicy("PrivateProfileRequirement", policy => policy .RequireAuthenticatedUser() .RequireRole(Role.Profile.ToRole()) .AddRequirements(new PrivateProfileRequirement(ClaimTypes.NameIdentifier))); });
的 调节器 强>
public class ProfileController : Controller { private readonly IAuthorizationService _authorizationService; public ProfileController(IAuthorizationService authorizationService) { _authorizationService = authorizationService; } }
的 行动 强>
public async Task<IActionResult> OnGetAsync(int id) { var profile = _profileRepository.Find(id); if (profile == null) { return new NotFoundResult(); } var authorizationResult = await _authorizationService .AuthorizeAsync(User, profile.Id, "PrivateProfileRequirement"); if (authorizationResult.Succeeded) { return View(); } return new ChallengeResult(); }
另请参阅基于声明的授权方法 - 包括从.NET 4.5开始。
http://leastprivilege.com/2012/10/26/using-claims-based-authorization-in-mvc-and-web-api/
我会考虑实现一个自定义 System.Web.Http.AuthorizeAttribute 您可以将其应用于需要此特定授权规则的操作。在自定义授权中,如果用户是Admins组的成员,或者他们是资源的作者,则可以允许访问。
编辑:
根据OP的编辑,允许我扩展我所说的内容。如果覆盖AuthorizeAttribute,则可以添加如下逻辑:
public class AuthorizeAdminsAndAuthors : System.Web.Http.AuthorizeAttribute { protected override bool IsAuthorized(HttpActionContext actionContext) { return currentUser.IsInRole("Admins") || IsCurrentUserAuthorOfPost(actionContext); } private bool IsCurrentUserAuthorOfPost(HttpActionContext actionContext) { // Get id for resource from actionContext // look up if user is author of this post return true; }
这是伪代码,但应传达这个想法。如果您有一个AuthorizeAttribute根据您的要求确定授权:当前请求来自帖子的作者或管理员,那么您可以将AuthorizeAdminsAndAuthors属性应用于您需要此级别授权的任何资源。所以你的资源看起来像:
[AuthorizeAdminsAndAuthors] public Resource GetResource(int id) { var resource = resourceRepository.Find(id); return resource; }
您需要外部授权。您希望将整个授权逻辑移动到单独的层或服务。
有几个框架 - 用不同的语言 - 可以让你这样做。在.NET世界中,如其他答案所示,您具有基于声明的授权。微软有一篇很棒的文章 这里 。
我建议你采用标准化方法,即XACML,可扩展访问控制标记语言。 XACML为您提供三件事:
如果我们再次访问您的示例,您将拥有以下内容:
public Resource GetResource(int id) { var resource = resourceRepository.Find(id); if (isAuthorized(User.Identity,resource)) { throw new HttpResponseException(HttpStatusCode.Unauthorized); } return resource; } public bool isAuthorized(User u, Resource r){ // Create XACML request here // Call out to PDP // return boolean decision }
您的PDP将包含以下规则:
XACML的好处是您可以独立于代码增加授权规则/逻辑。这意味着无论何时逻辑发生变化,您都不必触摸应用程序代码。 XACML还可以满足更多参数/属性 - 例如设备ID,IP,一天中的时间......最后,XACML并不特定于.NET。它适用于许多不同的框架。
您可以阅读XACML 这里 并靠我自己 博客 我在哪里写关于授权。维基百科在这个主题上也有一个不错的页面。