ASP.NET Core 认证与授权[7]:动态授权 (3)

如上,针对每一个权限项都定义一个对应的授权策略,然后,就可以在控制器中直接使用[Authorize]来完成授权:

[Authorize] public class UserController : Controller { [Authorize(Policy = Permissions.UserRead)] public ActionResult Index() { } [Authorize(Policy = Permissions.UserRead)] public ActionResult Details(int? id) { } [Authorize(Policy = Permissions.UserCreate)] public ActionResult Create() { return View(); } [Authorize(Policy = Permissions.UserCreate)] [HttpPost] [ValidateAntiForgeryToken] public IActionResult Create([Bind("Title")] User user) { } }

当然,我们也可以像基于资源的授权那样,在应用代码中调用IAuthorizationService完成授权,这样做的好处是无需定义策略,但是,显然一个一个来定义策略太过于繁琐。

还有一种更好方式,就是使用MVC过滤器来完成对IAuthorizationService的调用,下面就来演示一下。

自定义授权过滤器

我们可以参考上一章中介绍的《AuthorizeFilter》来自定义一个权限过滤器:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] public class PermissionFilter : Attribute, IAsyncAuthorizationFilter { public PermissionFilter(string name) { Name = name; } public string Name { get; set; } public async Task OnAuthorizationAsync(AuthorizationFilterContext context) { var authorizationService = context.HttpContext.RequestServices.GetRequiredService<IAuthorizationService>(); var authorizationResult = await authorizationService.AuthorizeAsync(context.HttpContext.User, null, new PermissionAuthorizationRequirement(Name)); if (!authorizationResult.Succeeded) { context.Result = new ForbidResult(); } } }

上面的实现非常简单,我们接受一个name参数,代表权限的名称,然后将权限名称转化为PermissionAuthorizationRequirement,最后直接调用 authorizationService 来完成授权。

接下来,我们就可以直接在控制器中使用PermissionFilter过滤器来完成基于权限的授权了:

[Authorize] public class UserController : Controller { [PermissionFilter(Permissions.UserRead)] public ActionResult Index() { return View(_userStore.GetAll()); } [PermissionFilter(Permissions.UserCreate)] public ActionResult Create() { } [PermissionFilter(Permissions.UserCreate)] [HttpPost] [ValidateAntiForgeryToken] public IActionResult Create([Bind("Title")] User user) { } [PermissionFilter(Permissions.UserUpdate)] public IActionResult Edit(int? id) { } [PermissionFilter(Permissions.UserUpdate)] [HttpPost] [ValidateAntiForgeryToken] public IActionResult Edit(int id, [Bind("Id,Title")] User user) { } } 在视图中使用授权

通常,在前端页面当中,我们也需要根据用户的权限来判断是否显示“添加”,“删除”等按钮,而不是让用户点击“添加”,再提示用户没有权限,这在 ASP.NET Core 中实现起来也非常简单。

我们可以直接在Razor视图中注入IAuthorizationService来检查用户权限:

@inject IAuthorizationService AuthorizationService @if ((await AuthorizationService.AuthorizeAsync(User, AuthorizationSample.Authorization.Permissions.UserCreate)).Succeeded) { <p> <a asp-action="Create">创建</a> </p> }

不过,上面的代码是通过策略名称来授权的,如果我们使用了上面创建的授权过滤器,而没有定义授权策略的话,需要使用如下方式来实现:

@inject IAuthorizationService AuthorizationService @if ((await AuthorizationService.AuthorizeAsync(User, new PermissionAuthorizationRequirement(AuthorizationSample.Authorization.Permissions.UserCreate))).Succeeded) { <p> <a asp-action="Create">创建</a> </p> }

我们也可以定义一个AuthorizationService的扩展方法,实现通过权限名称进行授权,这里就不再多说。

我们不能因为隐藏了操作按钮,就不在后端进行授权验证了,就像JS的验证一样,前端的验证就为了提升用户的体验,后端的验证在任何时候都是必不可少的。

总结

在大多数场景下,我们只需要使用授权策略就可以应对,而在授权策略不能满足我们的需求时,由于 ASP.NET Core 提供了一个统一的 IAuthorizationService 授权接口,这就使我们扩展起来也非常方便。ASP.NET Core 的授权部分到这来也就介绍完了,总的来说,要比ASP.NET 4.x的时候,简单,灵活很多,可见 ASP.NET Core 不仅仅是为了跨平台,而是为了适应现代应用程序的开发方式而做出的全新的设计,我们也应该用全新的思维去学习.NET Core,踏上时代的浪潮。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyxdpy.html