项目
版本

本文档有多个版本。请选择最适合您的选项。

UI
Database

Web 应用程序开发教程 - 第 5 部分:授权

权限

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

权限名称

一个权限必须有一个唯一的名称(一个 string)。最好的方式是将其定义为 const,以便我们可以重复使用该权限名称。

打开 Acme.BookStore.Application.Contracts 项目中的 BookStorePermissions 类(位于 Permissions 文件夹内),并添加新的权限名称:

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 并不强制要求你采用某种结构,但我们发现这种方式很有用。

权限定义

在使用权限之前,你应该先定义它们。

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

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"));
        
        // 仪表板权限
        bookStoreGroup.AddPermission(BookStorePermissions.Dashboard.Host, L("Permission:Dashboard"), MultiTenancySides.Host);
        bookStoreGroup.AddPermission(BookStorePermissions.Dashboard.Tenant, L("Permission:Dashboard"), MultiTenancySides.Tenant);

        // 图书权限
        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),以定义上面使用的本地化键:

"Permission:BookStore": "书店",
"Permission:Books": "图书管理",
"Permission:Books.Create": "创建新图书",
"Permission:Books.Edit": "编辑图书",
"Permission:Books.Delete": "删除图书"

本地化键的名称是任意的,没有强制规则。但我们更喜欢上面使用的约定。

权限管理 UI

一旦定义了权限,你就可以在权限管理模态框中看到它们。

进入 管理 -> 身份标识 -> 角色 页面,选择 admin 角色的 权限 操作以打开权限管理模态框:

bookstore-permissions-ui

授予你想要的权限并保存模态框。

提示:如果你运行 Acme.BookStore.DbMigrator 应用程序,新权限会自动授予 admin 角色。

授权

现在,你可以使用这些权限来授权图书管理操作。

应用层 & HTTP API

打开 BookAppService 类,并将策略名称设置为上面定义的权限名称:

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, // Book 实体
        BookDto, // 用于显示图书
        Guid, // Book 实体的主键
        PagedAndSortedResultRequestDto, // 用于分页/排序
        CreateUpdateBookDto>, // 用于创建/更新图书
    IBookAppService // 实现 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(参见自动 API 控制器)。

你将在开发作者管理功能时看到使用 [Authorize(...)] 属性的声明式授权。

Angular 路由守卫配置

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

打开 /src/app/book/book-routing.module.ts 并用以下内容替换:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { authGuard, permissionGuard } from '@abp/ng.core';
import { BookComponent } from './book.component';

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

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class BookRoutingModule {}
  • @abp/ng.core 导入了 authGuardpermissionGuard
  • 向路由定义添加了 canActivate: [authGuard, permissionGuard]

打开 /src/app/route.provider.ts 并为 /book-store 路由添加 requiredPolicy: 'BookStore.Books'/book-store 路由块应为以下内容:

{
  path: '/book-store',
  name: '::Menu:BookStore',
  iconClass: 'fas fa-book',
  order: 2,
  layout: eLayoutType.application,
  requiredPolicy: 'BookStore.Books',
},

打开 /src/app/route.provider.ts 并为 /books 路由添加 requiredPolicy: 'BookStore.Books'/books 路由块应为以下内容:

{
  path: '/books',
  name: '::Menu:Books',
  parentName: '::Menu:BookStore',
  layout: eLayoutType.application,
  requiredPolicy: 'BookStore.Books',
}

隐藏新建图书按钮

图书管理页面有一个新建图书按钮,如果当前用户没有图书创建权限,该按钮应该是不可见的。

bookstore-new-book-button-small

打开 /src/app/book/book.component.html 文件,并按如下所示替换创建按钮的 HTML 内容:

<!-- 添加 abpPermission 指令 -->
<button *abpPermission="'BookStore.Books.Create'" id="create" class="btn btn-primary" type="button" (click)="createBook()">
  <i class="fa fa-plus me-1"></i>
  <span>{{ '::NewBook' | abpLocalization }}</span>
</button>
  • 只需添加 *abpPermission="'BookStore.Books.Create'" 即可在当前用户没有权限时隐藏该按钮。

隐藏编辑和删除操作

图书管理页面中的图书表格每一行都有一个操作按钮。操作按钮包括编辑删除操作:

bookstore-edit-delete-actions

如果当前用户未被授予相关权限,我们应该隐藏某个操作。

打开 /src/app/book/book.component.html 文件,并按如下所示替换编辑和删除按钮的内容:

<!-- 添加 abpPermission 指令 -->
<button *abpPermission="'BookStore.Books.Edit'" ngbDropdownItem (click)="editBook(row.id)">
  {{ '::Edit' | abpLocalization }}
</button>

<!-- 添加 abpPermission 指令 -->
<button *abpPermission="'BookStore.Books.Delete'" ngbDropdownItem (click)="delete(row.id)">
  {{ '::Delete' | abpLocalization }}
</button>
  • 添加了 *abpPermission="'BookStore.Books.Edit'",如果当前用户没有编辑权限,则隐藏编辑操作。
  • 添加了 *abpPermission="'BookStore.Books.Delete'",如果当前用户没有删除权限,则隐藏删除操作。

在本文档中