Abp vnext Web应用程序开发教程 5 —— 授权

本文介绍如何使用ABP框架实现基于角色的权限管理,包括定义权限、授权HTTP API及Razor页面、前端权限验证等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于本教程

本教程基于版本3.1

在本教程系列中,您将构建一个名为Acme.BookStore的基于ABPWeb应用程序。该应用程序用于管理书籍及其作者的列表。它是使用以下技术开发的:

  • 实体框架核心作为ORM提供者。
  • MVC/Razor页面作为UI框架。

本教程分为以下部分:

第1部分:创建服务器端

第2部分:书籍列表页面

第3部分:创建、更新和删除书籍

第4部分:集成测试

第5部分:授权(此部分)

第6部分:作者:领领域层

第7部分:作者:数据库集成

第8部分:作者:应用程序层

第9部分:作者:用户界面

第10部分:书与作者的关系

下载源代码

MVC (Razor Pages) UI with EF Core

权限

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

权限定义

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

打开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"));

            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个权限。同样,CreateEditDeleteBookStorePermissions.Books.Default权限的子级。只有选择了父级,才能选择子级权限。

最后,编辑本地化文件(在Acme.BookStore.Domain.Shared项目Localization/BookStore文件夹下的en.json中)以定义上面使用的本地化键:

"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"

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

权限管理界面

定义权限后,您可以在权限管理模式下看到它们。

转到“Administration”->“Identity”->“Roles”页面,为管理员角色选择“权限”操作以打开权限管理模式:
在这里插入图片描述

授予所需的权限并保存模式。

授权

现在,您可以使用权限来授权书籍管理。

应用层和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, //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操作使用这些权限。这使应用程序服务安全,而且使HTTP API安全,因为如前所述,该服务自动用作HTTP API(请参阅auto API控制器)。

Razor页面

虽然保护HTTP API和应用程序服务的安全可防止未经授权的用户使用服务,但他们仍可以导航到书籍管理页面。尽管当页面首次对服务器进行AJAX调用时他们将获得授权异常,但我们也应该对页面进行授权,以获得更好的用户体验和安全性。

打开BookStoreWebModule并在ConfigureServices方法内添加以下代码块:

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文件并更改内容,如下所示:

@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为隐藏操作项。

打开Acme.BookStore.Web项目内部的Pages/Books/Index.js,然后向Edit操作添加一个visible选项,如下所示:

{
    text: l('Edit'),
    visible: abp.auth.isGranted('BookStore.Books.Edit'), //CHECK for the PERMISSION
    action: function (data) {
        editModal.open({ id: data.record.id });
    }
}

Delete操作执行相同的操作:

visible: abp.auth.isGranted('BookStore.Books.Delete')
  • abp.auth.isGranted(...) 用于检查之前定义的权限。

  • visible也可能会得到一个返回bool的函数,如果该值稍后会根据某些条件计算。

菜单项

即使我们已经保护了书籍管理页面的所有层,它仍然在应用程序的主菜单上可见。如果当前用户没有权限,我们应该隐藏菜单项。

打开BookStoreMenuContributor类,在下面找到代码块:

context.Menu.AddItem(
    new ApplicationMenuItem(
        "BooksStore",
        l["Menu:BookStore"],
        icon: "fa fa-book"
    ).AddItem(
        new ApplicationMenuItem(
            "BooksStore.Books",
            l["Menu:Books"],
            url: "/Books"
        )
    )
);

并用以下代码替换此代码块:

var bookStoreMenu = new ApplicationMenuItem(
    "BooksStore",
    l["Menu:BookStore"],
    icon: "fa fa-book"
);

context.Menu.AddItem(bookStoreMenu);

//CHECK the PERMISSION
if (await context.IsGrantedAsync(BookStorePermissions.Books.Default))
{
    bookStoreMenu.AddItem(new ApplicationMenuItem(
        "BooksStore.Books",
        l["Menu:Books"],
        url: "/Books"
    ));
}

下一部分

请参阅本教程的下一部分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值