Abp vNext 学习第六弹 - 授权 参考上一篇 :Abp vNext 学习(5) .
权限 ABP框架提供了一个基于ASP.NET Core授权基础架构的授权系统. 基于标准授权基础架构的一个主要功能是添加了 权限系统 , 这个系统允许定义权限并且根据角色, 用户或客户端启用/禁用权限.
权限名称 权限必须有唯一的名称 (一个 字符串
). 最好的方法是把它定义为一个 常量
, 这样我们就可以重用这个权限名称了.
打开 .Application.Contracts
项目中的 BookStorePermissions
类 (位于 Permissions 文件夹) 并替换为以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 namespace Acme.BookStore.Permissions { public static class BookStorePermissions { public const string GroupName = "BookStore" ; public static class Books { public const string Default = GroupName + ".Books" ; public const string Create = Default + ".Create" ; public const string Edit = Default + ".Edit" ; public const string Delete = Default + ".Delete" ; } } }
权限名称具有层次结构. 例如, “创建图书” 权限被定义为 BookStore.Books.Create
. ABP不强制必须如此, 但是建议这么做 ·.
权限定义 在使用权限前必须定义它们.
打开 .Application.Contracts
项目中的 BookStorePermissionDefinitionProvider
类 (位于 Permissions
文件夹) 并替换为以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 using Acme.BookStore.Localization;using Volo.Abp.Authorization.Permissions;using Volo.Abp.Localization;namespace Acme.BookStore.Permissions { public class BookStorePermissionDefinitionProvider : PermissionDefinitionProvider { public override void Define (IPermissionDefinitionContext context ) { var bookStoreGroup = context.AddGroup(BookStorePermissions.GroupName, L("Permission:BookStore" )); var booksPermission = bookStoreGroup.AddPermission(BookStorePermissions.Books.Default, L("Permission:Books" )); booksPermission.AddChild(BookStorePermissions.Books.Create, L("Permission:Books.Create" )); booksPermission.AddChild(BookStorePermissions.Books.Edit, L("Permission:Books.Edit" )); booksPermission.AddChild(BookStorePermissions.Books.Delete, L("Permission:Books.Delete" )); } private static LocalizableString L (string name ) { return LocalizableString.Create<BookStoreResource>(name); } } }
这个类定义了一个 权限组 (在UI上分组权限, 下文会看到) 和 权限组中的4个权限. 而且, 创建 , 编辑 和 删除 是 ß
权限的子权限. 仅当父权限被选择时, 子权限才能被选择.
最后, 编辑本地化文件 (.Domain.Shared
项目的 Localization/BookStore
文件夹中的 en.json
) 定义上面使用的本地化键:
1 2 3 4 5 "Permission:BookStore" : "Book Store" ,"Permission:Books" : "Book Management" ,"Permission:Books.Create" : "Creating new books" ,"Permission:Books.Edit" : "Editing the books" ,"Permission:Books.Delete" : "Deleting the books"
本地化键名可以是任意的, 并没有强制的规则. 但我们推荐上面使用的约定. 简体中文翻译请打开zh-Hans.json
文件 ,并将”Texts
“对象中对应的值替换为中文.
权限管理界面 完成权限定义后, 可以在权限管理模态窗口看到它们.
在管理 -> Identity -> 角色 页面, 选择admin角色的 权限 操作, 打开权限管理模态窗口
授予你希望的权限并保存.
提示: 如果运行 .DbMigrator
应用程序, 新权限会被自动授予admin.
授权 现在, 你可以使用权限授权图书管理.
应用层 和 HTTP API 打开 BookAppService
类, 设置策略名称为上面定义的权限名称.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 using System;using Acme.BookStore.Permissions;using Volo.Abp.Application.Dtos;using Volo.Abp.Application.Services;using Volo.Abp.Domain.Repositories;namespace Acme.BookStore.Books { public class BookAppService : CrudAppService < Book , //The Book entity BookDto , //Used to show books Guid , //Primary key of the book entity PagedAndSortedResultRequestDto , //Used for paging /sorting CreateUpdateBookDto >, IBookAppService { public BookAppService (IRepository<Book, Guid> repository ) : base (repository ) { GetPolicyName = BookStorePermissions.Books.Default; GetListPolicyName = BookStorePermissions.Books.Default; CreatePolicyName = BookStorePermissions.Books.Create; UpdatePolicyName = BookStorePermissions.Books.Edit; DeletePolicyName = BookStorePermissions.Books.Delete; } } }
加入代码到构造器. 基类中的 CrudAppService
自动在CRUD操作中使用这些权限. 这不仅实现了 应用服务 的安全性, 也实现了 HTTP API 安全性, 因为如前解释的, HTTP API 自动使用这些服务。
在稍后开发作者管理功能时, 你将会看到声明式授权, 使用 [Authorize(...)]
特性.
Razor 页面 虽然安全的 HTTP API和应用服务阻止未授权用户使用服务, 但他们依然可以导航到图书管理页面. 虽然当页面发起第一个访问服务器的AJAX请求时会收到授权异常, 但为了更好的用户体验和安全性, 我们应该对页面进行授权.
打开 BookStoreWebModule
在 ConfigureServices
方法中加入以下代码:
1 2 3 4 5 6 Configure<RazorPagesOptions>(options => { options.Conventions.AuthorizePage("/Books/Index" , BookStorePermissions.Books.Default); options.Conventions.AuthorizePage("/Books/CreateModal" , BookStorePermissions.Books.Create); options.Conventions.AuthorizePage("/Books/EditModal" , BookStorePermissions.Books.Edit); });
现在未授权用户会被重定向至登录页面 .
隐藏新建图书按钮 图书管理页面有一个 新建图书 按钮, 当用户没有 图书新建 权限时就不可见的.
打开 Pages/Books/Index.cshtml
文件, 替换内容为以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @page @using Acme.BookStore.Localization @using Acme.BookStore.Permissions @using Acme.BookStore.Web.Pages.Books @using Microsoft.AspNetCore.Authorization @using Microsoft.Extensions.Localization @model IndexModel @inject IStringLocalizer<BookStoreResource> L @inject IAuthorizationService AuthorizationService @section scripts { <abp-script src="/Pages/Books/Index.js" /> } <abp-card> <abp-card-header> <abp-row> <abp-column size-md="_6" > <abp-card-title>@L["Books" ]</abp-card-title> </abp-column> <abp-column size-md="_6" class ="text-right" > @if (await AuthorizationService.IsGrantedAsync(BookStorePermissions.Books.Create)) { <abp-button id="NewBookButton" text="@L[" NewBook"].Value" icon="plus" button-type="Primary" /> } </abp-column> </abp-row> </abp-card-header> <abp-card-body> <abp-table striped-rows="true" id="BooksTable" ></abp-table> </abp-card-body> </abp-card>
加入 @inject IAuthorizationService AuthorizationService
以访问授权服务.
使用 @if (await AuthorizationService.IsGrantedAsync(BookStorePermissions.Books.Create))
检查图书创建 权限, 条件显示 新建图书 按钮.
JavaScript端 图书管理页面中的图书表格每行都有操作按钮. 操作按钮包括 编辑 和 删除 操作:
如果用户没有权限, 应该隐藏相关的操作. 表格行中的操作有一个 visible
属性, 可以设置为 false
隐藏操作项.
打开 .Web
项目中的 Pages/Books/Index.js
, 为 Edit
操作加入 visible
属性:
1 2 3 4 5 6 7 { text : l('Edit' ), visible : abp.auth.isGranted('BookStore.Books.Edit' ), action : function (data ) { editModal.open({ id : data.record.id }); } }
对 Delete
操作进行同样的操作:
1 visible: abp.auth.isGranted('BookStore.Books.Delete' ),
abp.auth.isGranted(...)
检查前面定义的权限.
visible
也可以是一个返回 bool
值的函数. 这个函数可以稍后根据某些条件计算.
菜单项 即使我们在图书管理页面的所有层都控制了权限, 应用程序的主菜单依然会显示. 我们应该隐藏用户没有权限的菜单项.
打开 BookStoreMenuContributor
类, 找到下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 context.Menu.AddItem( new ApplicationMenuItem( "BooksStore" , l["Menu:BookStore" ], icon: "fa fa-book" ).AddItem( new ApplicationMenuItem( "BooksStore.Books" , l["Menu:Books" ], url: "/Books" ) ) );
替换为以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var bookStoreMenu = new ApplicationMenuItem( "BooksStore" , l["Menu:BookStore" ], icon: "fa fa-book" ); context.Menu.AddItem(bookStoreMenu); if (await context.IsGrantedAsync(BookStorePermissions.Books.Default)){ bookStoreMenu.AddItem(new ApplicationMenuItem( "BooksStore.Books" , l["Menu:Books" ], url: "/Books" )); }
Demo Codes
github commit
下一章 参阅的Abp vNext 学习(6) 。