Abp vNext - 应用开发系列之授权

在系列教程中,我们会构建一个基于ABP的Web应用程序,用于管理书籍及其作者列表

使用到的技术:

  • Entity Framework Core
  • Angular

本教程分为以下部分:

权限

ABP框架提供了一个基于 ASP.NET Core授权基础设施的授权系统。在标准授权基础架构之上添加的一个主要功能是权限系统,它允许定义权限,并启用/禁用每个角色、用户或客户端。

权限名称

权限必须具有唯一的名称 ( string ),将其定义为 const ,这样可以复用权限名称。

打开 Acme.BookStore.Application.Contracts 项目内( Permissions 在文件夹中)的 BookStorePermissions 类,并更改内容,如下所示:

这是定义权限名称的分层方式。例如,“创建书籍”权限名称定义为 BookStore.Books.Create

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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";
}
}

权限定义

在使用权限之前,应定义权限。

打开 Acme.BookStore.Application.Contracts 项目内( Permissions 在文件夹中)的 BookStorePermissionDefinitionProvider 类,并更改内容,

如下所示:

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
using Acme.BookStore.Localization;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;

namespace Acme.BookStore.Permissions;

public class BookStorePermissionDefinitionProvider : PermissionDefinitionProvider
{
public override void Define(IPermissionDefinitionContext context)
{
var bookStoreGroup = context.AddGroup(BookStorePermissions.GroupName, L("Permission:BookStore"));

bookStoreGroup.AddPermission(BookStorePermissions.Dashboard.Host, L("Permission:Dashboard"), MultiTenancySides.Host);
bookStoreGroup.AddPermission(BookStorePermissions.Dashboard.Tenant, L("Permission:Dashboard"), MultiTenancySides.Tenant);

//Define your own permissions here. Example:
//myGroup.AddPermission(BookStorePermissions.MyPermission1, L("Permission:MyPermission1"));

// 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 个权限。创建、编辑和删除是 BookStorePermissions.Books.Default 权限的子级。

只有选择了父级时,才能选择子权限。

编辑多语言文件(在 Acme.BookStore.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"

权限管理界面

定义权限后,可以在权限管理模块上看到。

转到“管理”->“身份”->“角色”页面,选择管理员角色的“权限”操作以打开权限管理模式:

根据所需的权限进行设置并保存。

permissions

授权

使用权限来对图书管理接口授权。

应用层

打开 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
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>, //Used to create/update a book
IBookAppService //implement the 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操作匹配这些权限,这里无需对每个接口进行权限配置。

权限守卫

UI的第一步是防止未经授权的用户看到书籍菜单项并进入书籍管理页面。

/src/app/book/book-routing.module.ts 注册:

1
2
3
4
5
6
7
8
9
10
11
12
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { BookComponent } from './book.component';
import { authGuard, permissionGuard } from '@abp/ng.core';

const routes: Routes = [{ path: '', component: BookComponent,canActivate: [authGuard, permissionGuard] }];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class BookRoutingModule { }
  • 导入authGuard,permissionGuard,并添加到路由定义中

打开 /src/app/route.provider.ts ,添加菜单权限requiredPolicy,如下:

requiredPolicy: ‘BookStore.Books’,定义菜单权限

1
2
3
4
5
6
7
{
path: '/books',
name: '::Menu:Books',
parentName: '::Menu:BookStore',
layout: eLayoutType.application,
requiredPolicy: 'BookStore.Books',
}

按钮权限

在页面中使用*abpPermission校验权限

打开 /src/app/book/book.component.html ,给操作按钮加入权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Create Btn
<button *abpPermission="'BookStore.Books.Create'" id="create" class="btn btn-primary" type="button" (click)="createBook()">
<i class="fa fa-plus mr-1"></i>
<span>{{ '::NewBook' | abpLocalization }}</span>
</button>

// Edit Btn
<button *abpPermission="'BookStore.Books.Edit'" ngbDropdownItem (click)="editBook(row.id)">
{{ '::Edit' | abpLocalization }}
</button>

// Delete Btn
<button *abpPermission="'BookStore.Books.Delete'" ngbDropdownItem (click)="delete(row.id)">
{{ '::Delete' | abpLocalization }}
</button>

当用户没有权限时,按钮则会隐藏

abpPermission

下一节

教程下一节