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 角色的 权限 操作以打开权限管理模态框:
授予你想要的权限并保存模态框。
提示:如果你运行
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导入了authGuard和permissionGuard。 - 向路由定义添加了
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',
}
隐藏新建图书按钮
图书管理页面有一个新建图书按钮,如果当前用户没有图书创建权限,该按钮应该是不可见的。
打开 /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'"即可在当前用户没有权限时隐藏该按钮。
隐藏编辑和删除操作
图书管理页面中的图书表格每一行都有一个操作按钮。操作按钮包括编辑和删除操作:
如果当前用户未被授予相关权限,我们应该隐藏某个操作。
打开 /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'",如果当前用户没有删除权限,则隐藏删除操作。
抠丁客





