Abp vnext 授权(Authorization)

介绍

授权用于检查是否允许用户在应用程序中执行某些特定操作。

ABP通过将权限添加为自动策略来扩展ASP.NET Core授权,并允许授权系统也可在应用程序服务中使用。

因此,所有ASP.NET Core授权功能和文档在基于ABP的应用程序中均有效。本文档重点介绍在ASP.NET Core授权功能之上添加的功能。

授权属性

ASP.NET Core定义了可用于操作,控制器或页面的Authorize属性。ABP还允许您对应用程序服务使用相同的属性。

例:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Services;

namespace Acme.BookStore
{
    [Authorize]
    public class AuthorAppService : ApplicationService, IAuthorAppService
    {
        public Task<List<AuthorDto>> GetListAsync()
        {
            ...
        }

        [AllowAnonymous]
        public Task<AuthorDto> GetAsync(Guid id)
        {
            ...
        }

        [Authorize("BookStore_Author_Create")]
        public Task CreateAsync(CreateAuthorDto input)
        {
            ...
        }
    }
}
  • Authorize属性强制用户登录到应用程序以使用AuthorAppService方法。因此,GetListAsync方法仅对经过身份验证的用户可用。

  • AllowAnonymous禁止身份认证。因此,GetAsync方法适用于所有人,包括未经授权的用户。

  • [Authorize("BookStore_Author_Create")]定义一个策略(请参阅基于策略的授权),选中该策略以授权当前用户。

“BookStore_Author_Create”是任意策略名称。如果您声明这样的属性,则ASP.NET Core授权系统希望在此之前定义一个策略。

当然,您可以按照ASP.NET Core文档中所述实施策略。但是,对于简单的真/假条件(例如,是否向用户授予了策略),ABP定义了权限系统,这将在下一部分中进行说明。

权限系统

权限是为特定用户,角色或客户端授予或禁止的简单策略。

定义权限

要定义权限,请创建一个继承自PermissionDefinitionProvider的类,如下所示:

using Volo.Abp.Authorization.Permissions;

namespace Acme.BookStore.Permissions
{
    public class BookStorePermissionDefinitionProvider : PermissionDefinitionProvider
    {
        public override void Define(IPermissionDefinitionContext context)
        {
            var myGroup = context.AddGroup("BookStore");

            myGroup.AddPermission("BookStore_Author_Create");
        }
    }
}

ABP自动发现此类。无需其他配置!

您通常在应用程序项目Application.Contracts中定义此类。启动模板已经附带了一个空类,名为YourProjectNamePermissionDefinitionProvider,您可以从中开始。

Define方法中,您首先需要添加权限组或获取现有组,然后向该组添加权限

定义权限后,它就可以在ASP.NET Core授权系统中用作策略名称。它也将在UI中可见。查看角色的权限对话框:
在这里插入图片描述

  • “BookStore”组显示为左侧的新选项卡。

  • 右侧的“BookStore_Author_Create”是权限名称。您可以授予或禁止该角色。

保存对话框时,该对话框将保存到数据库中并在授权系统中使用。

安装身份(identity)模块后,上面的屏幕将可用,该模块主要用于用户和角色管理。启动模板预装有身份(identity)模块。

本地化权限名称

UI的“BookStore_Author_Create”不是一个好的权限名称。幸运的是,AddPermissionAddGroup方法可以采用LocalizableString作为第二个参数:

var myGroup = context.AddGroup(
    "BookStore",
    LocalizableString.Create<BookStoreResource>("BookStore")
);

myGroup.AddPermission(
    "BookStore_Author_Create",
    LocalizableString.Create<BookStoreResource>("Permission:BookStore_Author_Create")
);

然后,您可以在本地化文件中为“BookStore”和“Permission:BookStore_Author_Create”键定义文本:

"BookStore": "Book Store",
"Permission:BookStore_Author_Create": "Creating a new author"

有关更多信息,请参阅本地化系统上的本地化文档

本地化的UI如下所示:
在这里插入图片描述

多租户

ABP支持多租户作为头等公民。您可以在定义新权限时定义多租户选项。它获取以下定义的三个值之一:

  • Host:权限仅适用于宿主。

  • Tenant:权限仅适用于租户。

  • Both(默认):权限仅适用于宿主和租户。

如果您的应用程序不是多租户的,则可以忽略此选项。

要设置多租户方选项,请传递给AddPermission方法第三个参数:

myGroup.AddPermission(
    "BookStore_Author_Create",
    LocalizableString.Create<BookStoreResource>("Permission:BookStore_Author_Create"),
    multiTenancySide: MultiTenancySides.Tenant //set multi-tenancy side!
);

启用/禁用权限

默认情况下启用权限。可以禁用权限。禁用权限将被禁止给每个人。您仍然可以检查权限,但始终会返回禁止状态。

定义示例:

myGroup.AddPermission("Author_Management", isEnabled: false);

通常,您不需要定义禁用的权限(除非您暂时想禁用应用程序的功能)。但是,您可能需要禁用在依赖模块中定义的权限。这样,您可以禁用相关的应用程序功能。有关示例用法,请参见下面的“更改从属模块的权限定义”部分。

注意:检查未定义的权限将引发异常,而禁用的权限检查仅返回禁止(false)。

子权限

权限可能具有子权限。当您要创建一个层次结构的权限树时,它特别有用,该树中的权限可能具有其他子权限,这些权限仅在已授予父权限的情况下才可用。

定义示例:

var authorManagement = myGroup.AddPermission("Author_Management");
authorManagement.AddChild("Author_Management_Create_Books");
authorManagement.AddChild("Author_Management_Edit_Books");
authorManagement.AddChild("Author_Management_Delete_Books");

UI上的结果如下所示(您可能希望本地化应用程序的权限):
在这里插入图片描述

对于示例代码,假定授予“Author_Management”权限的角色/用户可能具有其他权限。然后可以如下所示定义检查权限的典型应用程序服务:

[Authorize("Author_Management")]
public class AuthorAppService : ApplicationService, IAuthorAppService
{
    public Task<List<AuthorDto>> GetListAsync()
    {
        ...
    }

    public Task<AuthorDto> GetAsync(Guid id)
    {
        ...
    }

    [Authorize("Author_Management_Create_Books")]
    public Task CreateAsync(CreateAuthorDto input)
    {
        ...
    }

    [Authorize("Author_Management_Edit_Books")]
    public Task UpdateAsync(CreateAuthorDto input)
    {
        ...
    }

    [Authorize("Author_Management_Delete_Books")]
    public Task DeleteAsync(CreateAuthorDto input)
    {
        ...
    }
}
  • GetListAsyncGetAsync将提供给用户,如果他们有Author_Management权限授予。

  • 其他方法需要其他权限。

通过自定义策略覆盖权限

如果使用权限的相同名称定义策略并将其注册到ASP.NET Core授权系统,则您的策略将覆盖现有的权限。这是扩展对在应用程序中使用的预构建模块的授权的有效方法。

请参阅基于策略的授权文档,以了解如何定义自定义策略。

更改从属模块的权限定义

PermissionDefinitionProvider派生的类(就像上面的示例一样)也可以获取现有的权限定义(由依赖模块定义)并更改其定义。

例:

context
    .GetPermissionOrNull(IdentityPermissions.Roles.Delete)
    .IsEnabled = false;

在权限定义提供程序中编写此代码时,它将找到身份模块的“角色删除”权限并禁用了该权限,因此没有人可以在应用程序上删除角色。

提示:最好检查GetPermissionOrNull方法返回的值,因为如果未定义给定的权限,则该值可能返回null

IAuthorizationService

ASP.NET Core提供了可用于检查授权的IAuthorizationService。注入后,可以在代码中使用它来有条件地控制授权。

例:

public async Task CreateAsync(CreateAuthorDto input)
{
    var result = await AuthorizationService
        .AuthorizeAsync("Author_Management_Create_Books");
    if (result.Succeeded == false)
    {
        //throw exception
        throw new AbpAuthorizationException("...");
    }

    //continue to the normal flow...
}

当您从ABP的ApplicationService基类派生时,AuthorizationService可以作为属性使用。由于它广泛用于应用程序服务中,因此为您预先注入了ApplicationService。否则,您可以将其直接注入您的类。

由于这是一个典型的代码块,因此ABP提供了扩展方法来简化它。

例:

public async Task CreateAsync(CreateAuthorDto input)
{
    await AuthorizationService.CheckAsync("Author_Management_Create_Books");

    //continue to the normal flow...
}

如果未为给定权限授予当前用户/客户端,则CheckAsync扩展方法将抛出AbpAuthorizationException异常。还有IsGrantedAsync扩展方法返回truefalse

IAuthorizationService对于AuthorizeAsync方法有一些重载。这些在ASP.NET Core授权文档中进行了说明。

提示:尽可能使用Authorize属性,因为它是声明性的且简单。使用IAuthorizationService,如果你需要条件的检查权限,并运行基于权限检查业务代码。

在JavaScript中检查权限

您可能需要在客户端检查策略/权限。

MVC用户界面

对于ASP.NET Core MVC / Razor Pages应用程序,可以使用abp.auth API。

示例:检查是否已为当前用户授予给定权限

abp.auth.isGranted('MyPermissionName');

Angular UI

请参阅Angular UI 的权限管理文档

权限管理

权限管理通常由管理员用户使用权限管理模式完成:
在这里插入图片描述

如果需要通过代码管理权限,请注入和使用IPermissionManager,如下所示:

public class MyService : ITransientDependency
{
    private readonly IPermissionManager _permissionManager;

    public MyService(IPermissionManager permissionManager)
    {
        _permissionManager = permissionManager;
    }

    public async Task GrantPermissionForUserAsync(Guid userId, string permissionName)
    {
        await _permissionManager.SetForUserAsync(userId, permissionName, true);
    }

    public async Task ProhibitPermissionForUserAsync(Guid userId, string permissionName)
    {
        await _permissionManager.SetForUserAsync(userId, permissionName, false);
    }
}

SetForUserAsync设置用户权限的值(true/false)。还有更多扩展方法,例如SetForRoleAsyncSetForClientAsync

IPermissionManager由权限管理模块定义。有关更多信息,请参阅权限管理模块文档

高级主题

权限值提供程序

权限检查系统是可扩展的。从PermissionValueProvider(或实现IPermissionValueProvider)派生的任何类都可以参与权限检查。有三个预定义的值提供程序:

  • UserPermissionValueProvider检查是否为当前用户授予了给定的权限。它从当前声明(claims)中获取用户id。用户声明(claims)名称是使用AbpClaimTypes.UserIdstatic属性定义的。

  • RolePermissionValueProvider检查是否为给定权限授予当前用户的任何角色。它从当前声明(claims)中获取角色名称。角色声明(claims)名称是使用AbpClaimTypes.Rolestatic属性定义的。

  • ClientPermissionValueProvider检查是否为当前客户端授予了给定的权限。这在当前没有用户的机器对机器的交互中特别有用。它从当前声明(claims)中获取客户id。客户声明(claims)名称是使用AbpClaimTypes.ClientIdstatic属性定义的。

您可以通过定义自己的权限值提供程序来扩展权限检查系统。

例:

public class SystemAdminPermissionValueProvider : PermissionValueProvider
{
    public SystemAdminPermissionValueProvider(IPermissionStore permissionStore)
        : base(permissionStore)
    {
    }

    public override string Name => "SystemAdmin";

    public override async Task<PermissionGrantResult>
           CheckAsync(PermissionValueCheckContext context)
    {
        if (context.Principal?.FindFirst("User_Type")?.Value == "SystemAdmin")
        {
            return PermissionGrantResult.Granted;
        }

        return PermissionGrantResult.Undefined;
    }
}

此提供程序允许具有SystemAdmin值的User_Type声明(claims)的用户获得所有权限。通常IPermissionStore在权限值提供程序中使用当前声明(claims)。

权限值提供程序应从CheckAsync方法返回以下值之一:

  • PermissionGrantResult.Granted返回以授予用户权限。如果任何提供程序返回Granted,则结果为Granted,如果没有其他提供程序则返回Prohibited

  • PermissionGrantResult.Prohibited返回以禁止用户获得权限。如果任何提供程序返回Prohibited,结果将始终为Prohibited。其他提供程序返回什么都无所谓。

  • 如果此值提供程序无法决定权限值,则返回PermissionGrantResult.Undefined。返回此值以让其他提供者检查权限。

定义提供程序后,应将其添加到AbpPermissionOptions,如下所示:

Configure(options =>
{
options.ValueProviders.Add();
});
C#

权限存储

IPermissionStore是唯一需要从持久性源(通常是数据库系统)读取权限值的接口。权限管理模块将实现它并预安装在应用程序启动模板中。有关更多信息,请参阅权限管理模块文档

AlwaysAllowAuthorizationService

AlwaysAllowAuthorizationService是用于绕过授权服务的类。它通常用于可能要禁用授权系统的集成测试中。

使用IServiceCollection.AddAlwaysAllowAuthorization()扩展方法来注册AlwaysAllowAuthorizationService依赖注入系统:

public override void ConfigureServices(ServiceConfigurationContext context)
{
    context.Services.AddAlwaysAllowAuthorization();
}

启动模板集成测试已完成此操作。

也可以看看

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值