Browse Source

complete resource-based-authorization document

pull/24679/head
EngincanV 3 weeks ago
parent
commit
d554cbb822
  1. 94
      docs/en/framework/fundamentals/authorization/index.md
  2. 320
      docs/en/framework/fundamentals/authorization/resource-based-authorization.md
  3. BIN
      docs/en/images/resource-based-permission.gif
  4. 303
      docs/en/modules/permission-management.md

94
docs/en/framework/fundamentals/authorization/index.md

@ -9,13 +9,15 @@
Authorization is used to check if a user is allowed to perform some specific operations in the application.
ABP extends [ASP.NET Core Authorization](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/introduction) by adding **permissions** as auto [policies](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies) and allowing authorization system to be usable in the **[application services](../architecture/domain-driven-design/application-services.md)** too.
ABP extends [ASP.NET Core Authorization](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/introduction) by adding **permissions** as auto [policies](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies) and allowing authorization system to be usable in the **[application services](../../architecture/domain-driven-design/application-services.md)** too.
So, all the ASP.NET Core authorization features and the documentation are valid in an ABP based application. This document focuses on the features that are added on top of ASP.NET Core authorization features.
ABP supports two types of permissions: **Standard permissions** apply globally (e.g., "can create documents"), while **resource-based permissions** target specific instances (e.g., "can edit Document #123"). This document covers standard permissions; see [Resource-Based Authorization](./resource-based-authorization.md) for fine-grained, per-resource access control.
## Authorize Attribute
ASP.NET Core defines the [**Authorize**](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/simple) attribute that can be used for an action, a controller or a page. ABP allows you to use the same attribute for an [application service](../architecture/domain-driven-design/application-services.md) too.
ASP.NET Core defines the [**Authorize**](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/simple) attribute that can be used for an action, a controller or a page. ABP allows you to use the same attribute for an [application service](../../architecture/domain-driven-design/application-services.md) too.
Example:
@ -87,9 +89,11 @@ namespace Acme.BookStore.Permissions
> ABP automatically discovers this class. No additional configuration required!
> You typically define this class inside the `Application.Contracts` project of your [application](../../solution-templates/layered-web-application). The startup template already comes with an empty class named *YourProjectNamePermissionDefinitionProvider* that you can start with.
> You typically define this class inside the `Application.Contracts` project of your [application](../../../solution-templates/layered-web-application/index.md). The startup template already comes with an empty class named *YourProjectNamePermissionDefinitionProvider* that you can start with.
In the `Define` method, you first need to add a **permission group** (or get an existing group), then add **permissions** to this group using the `AddPermission` method.
In the `Define` method, you first need to add a **permission group** or get an existing group then add **permissions** to this group.
> For resource-specific fine-grained permissions, use the `AddResourcePermission` method instead. See [Resource-Based Authorization](./resource-based-authorization.md) for details.
When you define a permission, it becomes usable in the ASP.NET Core authorization system as a **policy** name. It also becomes visible in the UI. See permissions dialog for a role:
@ -100,6 +104,8 @@ When you define a permission, it becomes usable in the ASP.NET Core authorizatio
When you save the dialog, it is saved to the database and used in the authorization system.
> **Note:** Only standard (global) permissions are shown in this dialog. Resource-based permissions are managed through the [Resource Permission Management Dialog](../../../modules/permission-management.md#resource-permission-management-dialog) on individual resource instances.
> The screen above is available when you have installed the identity module, which is basically used for user and role management. Startup templates come with the identity module pre-installed.
#### Localizing the Permission Name
@ -125,15 +131,15 @@ Then you can define texts for "BookStore" and "Permission:BookStore_Author_Creat
"Permission:BookStore_Author_Create": "Creating a new author"
```
> For more information, see the [localization document](./localization.md) on the localization system.
> For more information, see the [localization document](../localization.md) on the localization system.
The localized UI will be as seen below:
![authorization-new-permission-ui-localized](../../images/authorization-new-permission-ui-localized.png)
![authorization-new-permission-ui-localized](../../../images/authorization-new-permission-ui-localized.png)
#### Multi-Tenancy
ABP supports [multi-tenancy](../architecture/multi-tenancy) as a first class citizen. You can define multi-tenancy side option while defining a new permission. It gets one of the three values defined below:
ABP supports [multi-tenancy](../../architecture/multi-tenancy/index.md) as a first class citizen. You can define multi-tenancy side option while defining a new permission. It gets one of the three values defined below:
- **Host**: The permission is available only for the host side.
- **Tenant**: The permission is available only for the tenant side.
@ -180,7 +186,7 @@ authorManagement.AddChild("Author_Management_Delete_Books");
The result on the UI is shown below (you probably want to localize permissions for your application):
![authorization-new-permission-ui-hierarcy](../../images/authorization-new-permission-ui-hierarcy.png)
![authorization-new-permission-ui-hierarcy](../../../images/authorization-new-permission-ui-hierarcy.png)
For the example code, it is assumed that a role/user with "Author_Management" permission granted may have additional permissions. Then a typical application service that checks permissions can be defined as shown below:
@ -229,7 +235,7 @@ See [policy based authorization](https://docs.microsoft.com/en-us/aspnet/core/se
### Changing Permission Definitions of a Depended Module
A class deriving from the `PermissionDefinitionProvider` (just like the example above) can also get existing permission definitions (defined by the depended [modules](../architecture/modularity/basics.md)) and change their definitions.
A class deriving from the `PermissionDefinitionProvider` (just like the example above) can also get existing permission definitions (defined by the depended [modules](../../architecture/modularity/basics.md)) and change their definitions.
Example:
@ -247,12 +253,12 @@ When you write this code inside your permission definition provider, it finds th
You may want to disable a permission based on a condition. Disabled permissions are not visible on the UI and always returns `prohibited` when you check them. There are two built-in conditional dependencies for a permission definition;
* A permission can be automatically disabled if a [Feature](../infrastructure/features.md) was disabled.
* A permission can be automatically disabled if a [Global Feature](../infrastructure/global-features.md) was disabled.
* A permission can be automatically disabled if a [Feature](../../infrastructure/features.md) was disabled.
* A permission can be automatically disabled if a [Global Feature](../../infrastructure/global-features.md) was disabled.
In addition, you can create your custom extensions.
#### Depending on a Features
#### Depending on Features
Use the `RequireFeatures` extension method on your permission definition to make the permission available only if a given feature is enabled:
@ -261,7 +267,7 @@ myGroup.AddPermission("Book_Creation")
.RequireFeatures("BookManagement");
````
#### Depending on a Global Feature
#### Depending on Global Features
Use the `RequireGlobalFeatures` extension method on your permission definition to make the permission available only if a given feature is enabled:
@ -272,13 +278,13 @@ myGroup.AddPermission("Book_Creation")
#### Creating a Custom Permission Dependency
`PermissionDefinition` supports state check, Please refer to [Simple State Checker's documentation](../infrastructure/simple-state-checker.md)
`PermissionDefinition` supports state check, please refer to [Simple State Checker's documentation](../../infrastructure/simple-state-checker.md)
## IAuthorizationService
ASP.NET Core provides the `IAuthorizationService` that can be used to check for authorization. Once you inject, you can use it in your code to conditionally control the authorization.
ASP.NET Core provides the `IAuthorizationService` that can be used to check for authorization. Once you inject it, you can use it in your code to conditionally control the authorization.
Example:
**Example:**
```csharp
public async Task CreateAsync(CreateAuthorDto input)
@ -295,7 +301,7 @@ public async Task CreateAsync(CreateAuthorDto input)
}
```
> `AuthorizationService` is available as a property when you derive from ABP's `ApplicationService` base class. Since it is widely used in application services, `ApplicationService` pre-injects it for you. Otherwise, you can directly [inject](./dependency-injection.md) it into your class.
> `AuthorizationService` is available as a property when you derive from ABP's `ApplicationService` base class. Since it is widely used in application services, `ApplicationService` pre-injects it for you. Otherwise, you can directly [inject](../dependency-injection.md) it into your class.
Since this is a typical code block, ABP provides extension methods to simplify it.
@ -320,15 +326,15 @@ public async Task CreateAsync(CreateAuthorDto input)
See the following documents to learn how to re-use the authorization system on the client side:
* [ASP.NET Core MVC / Razor Pages UI: Authorization](../ui/mvc-razor-pages/javascript-api/auth.md)
* [Angular UI Authorization](../ui/angular/authorization/index.md)
* [Blazor UI Authorization](../ui/blazor/authorization/index.md)
* [ASP.NET Core MVC / Razor Pages UI: Authorization](../../ui/mvc-razor-pages/javascript-api/auth.md)
* [Angular UI Authorization](../../ui/angular/authorization/index.md)
* [Blazor UI Authorization](../../ui/blazor/authorization/index.md)
## Permission Management
Permission management is normally done by an admin user using the permission management modal:
![authorization-new-permission-ui-localized](../../images/authorization-new-permission-ui-localized.png)
![authorization-new-permission-ui-localized](../../../images/authorization-new-permission-ui-localized.png)
If you need to manage permissions by code, inject the `IPermissionManager` and use as shown below:
@ -356,13 +362,13 @@ public class MyService : ITransientDependency
`SetForUserAsync` sets the value (true/false) for a permission of a user. There are more extension methods like `SetForRoleAsync` and `SetForClientAsync`.
`IPermissionManager` is defined by the permission management module. See the [permission management module documentation](../../modules/permission-management.md) for more information.
`IPermissionManager` is defined by the Permission Management module. For resource-based permissions, use `IResourcePermissionManager` instead. See the [Permission Management Module documentation](../../../modules/permission-management.md) for more information.
## Advanced Topics
### Permission Value Providers
Permission checking system is extensible. Any class derived from `PermissionValueProvider` (or implements `IPermissionValueProvider`) can contribute to the permission check. There are three pre-defined value providers:
The permission checking system is extensible. Any class derived from `PermissionValueProvider` (or implements `IPermissionValueProvider`) can contribute to the permission check. There are three pre-defined value providers:
- `UserPermissionValueProvider` checks if the current user is granted for the given permission. It gets user id from the current claims. User claim name is defined with the `AbpClaimTypes.UserId` static property.
- `RolePermissionValueProvider` checks if any of the roles of the current user is granted for the given permission. It gets role names from the current claims. Role claims name is defined with the `AbpClaimTypes.Role` static property.
@ -412,15 +418,35 @@ Configure<AbpPermissionOptions>(options =>
});
```
### Resource Permission Value Providers
Similar to standard permission value providers, you can extend the resource permission checking system by creating custom **resource permission value providers**. ABP provides two built-in resource permission value providers:
* `UserResourcePermissionValueProvider`: Checks permissions granted directly to users for a specific resource.
* `RoleResourcePermissionValueProvider`: Checks permissions granted to roles for a specific resource.
You can create custom providers by implementing `IResourcePermissionValueProvider` or inheriting from `ResourcePermissionValueProvider`. Register them using:
```csharp
Configure<AbpPermissionOptions>(options =>
{
options.ResourceValueProviders.Add<YourCustomResourcePermissionValueProvider>();
});
```
> See the [Permission Management Module](../../../modules/permission-management.md#resource-permission-value-providers) documentation for detailed examples.
### Permission Store
`IPermissionStore` is the only interface that needs to be implemented to read the value of permissions from a persistence source, generally a database system. The Permission Management module implements it and pre-installed in the application startup template. See the [permission management module documentation](../../modules/permission-management.md) for more information
`IPermissionStore` is the interface that needs to be implemented to read the value of permissions from a persistence source, generally a database system. The Permission Management module implements it and is pre-installed in the application startup template. See the [Permission Management Module documentation](../../../modules/permission-management.md) for more information.
For resource-based permissions, `IResourcePermissionStore` serves the same purpose, storing and retrieving permissions for specific resource instances.
### AlwaysAllowAuthorizationService
`AlwaysAllowAuthorizationService` is a class that is used to bypass the authorization service. It is generally used in integration tests where you may want to disable the authorization system.
Use `IServiceCollection.AddAlwaysAllowAuthorization()` extension method to register the `AlwaysAllowAuthorizationService` to the [dependency injection](./dependency-injection.md) system:
Use `IServiceCollection.AddAlwaysAllowAuthorization()` extension method to register the `AlwaysAllowAuthorizationService` to the [dependency injection](../../dependency-injection.md) system:
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
@ -466,20 +492,24 @@ public static class CurrentUserExtensions
}
```
> If you use OpenIddict please see [Updating Claims in Access Token and ID Token](../../modules/openiddict#updating-claims-in-access_token-and-id_token).
> If you use OpenIddict please see [Updating Claims in Access Token and ID Token](../../../modules/openiddict#updating-claims-in-access_token-and-id_token).
## Resource-Based Authorization
ABP also supports **resource-based authorization** for fine-grained access control on specific resources. While the standard permission system grants permissions at a general level (e.g., "can edit documents"), resource-based authorization allows you to grant permissions for a specific document, project, or any other entity rather than granting a permission for all of them.
While this document covers standard (global) permissions, ABP also supports **resource-based authorization** for fine-grained access control on specific resource instances. Resource-based authorization allows you to grant permissions for a specific document, project, or any other entity rather than granting a permission for all resources of that type.
**Example scenarios:**
For example, you can grant a user permission to edit only a particular document, or allow a project manager to manage only their assigned projects.
* Allow users to edit **only their own** blog posts or documents
* Grant access to **specific projects** based on team membership
* Implement document sharing where **different users have different access levels** to the same document
> See the [Resource-Based Authorization](./resource-based-authorization.md) document for details.
> See the [Resource-Based Authorization](./resource-based-authorization.md) document for implementation details.
## See Also
* [Resource-Based Authorization](./resource-based-authorization.md)
* [Permission Management Module](../../modules/permission-management.md)
* [ASP.NET Core MVC / Razor Pages JavaScript Auth API](../ui/mvc-razor-pages/javascript-api/auth.md)
* [Permission Management in Angular UI](../ui/angular/Permission-Management.md)
* [Permission Management Module](../../../modules/permission-management.md)
* [ASP.NET Core MVC / Razor Pages JavaScript Auth API](../../ui/mvc-razor-pages/javascript-api/auth.md)
* [Permission Management in Angular UI](../../ui/angular/Permission-Management.md)
* [Video tutorial](https://abp.io/video-courses/essentials/authorization)

320
docs/en/framework/fundamentals/authorization/resource-based-authorization.md

@ -7,7 +7,7 @@
# Resource-Based Authorization
Resource-based authorization is a powerful feature that enables fine-grained access control based on specific resource instances. While the standard [permission system](./index.md) grants permissions at a general level (e.g., "can edit documents"), resource-based authorization allows you to grant permissions for a **specific** document, project, or any other entity rather than granting a permission for all of them.
**Resource-Based Authorization** is a powerful feature that enables fine-grained access control based on specific resource instances. While the standard [authorization system](./index.md) grants permissions at a general level (e.g., "can edit documents"), resource-based authorization allows you to grant permissions for a **specific** document, project, or any other entity rather than granting a permission for all of them.
## When to Use Resource-Based Authorization?
@ -64,7 +64,8 @@ namespace Acme.BookStore.Permissions
name: "BookStore_Document_View",
resourceName: "BookStore.Document",
managementPermissionName: "BookStore_Document_ManagePermissions",
displayName: LocalizableString.Create<BookStoreResource>("Permission:Document:View")
displayName: LocalizableString.Create<BookStoreResource>("Permission:Document:View"),
multiTenancySide: MultiTenancySides.Tenant
);
context.AddResourcePermission(
@ -91,10 +92,11 @@ The `AddResourcePermission` method requires the following parameters:
* `resourceName`: An identifier for the resource type. This is typically the full name of the entity class (e.g., `BookStore.Document`).
* `managementPermissionName`: A standard permission that controls who can manage resource permissions. Users with this permission can grant/revoke resource permissions for specific resources.
* `displayName`: (Optional) A localized display name shown in the UI.
* `multiTenancySide`: (Optional) Specifies on which side of a multi-tenant application this permission can be used. Accepts `MultiTenancySides.Host` (only for the host side), `MultiTenancySides.Tenant` (only for tenants), or `MultiTenancySides.Both` (default, available on both sides).
### Checking Resource Permissions
Use the `IResourcePermissionChecker` service to check if the current user has a specific permission for a resource:
Use the `IResourcePermissionChecker` service to check if a user/role/client has a specific permission for a resource:
```csharp
using System;
@ -158,26 +160,23 @@ In this example, the `DocumentAppService` injects `IResourcePermissionChecker` a
#### Using with Entities (IKeyedObject)
ABP entities implement the `IKeyedObject` interface, which provides a `GetObjectKey()` method. This allows for a cleaner syntax when checking permissions:
ABP entities implement the `IKeyedObject` interface, which provides a `GetObjectKey()` method. For entities with a primary key, `GetObjectKey()` returns the key as a string. This enables convenient extension methods on `IResourcePermissionChecker`:
```csharp
public async Task<DocumentDto> GetAsync(Guid id)
{
var document = await _documentRepository.GetAsync(id);
// Using the entity directly - GetObjectKey() returns the entity's Id
if (!await _resourcePermissionChecker.IsGrantedAsync(
"BookStore_Document_View",
document))
{
throw new AbpAuthorizationException(
"You don't have permission to view this document.");
}
// Instead of this:
await _resourcePermissionChecker.IsGrantedAsync(
"BookStore_Document_View",
"BookStore.Document",
document.Id.ToString());
return ObjectMapper.Map<Document, DocumentDto>(document);
}
// You can write:
await _resourcePermissionChecker.IsGrantedAsync(
"BookStore_Document_View",
document);
```
> See the [Entities documentation](../../architecture/domain-driven-design/entities.md) for more information about the `IKeyedObject` interface.
#### Checking Multiple Permissions
You can check multiple permissions at once using the overload that accepts an array of permission names:
@ -205,290 +204,15 @@ public async Task<DocumentPermissionsDto> GetPermissionsAsync(Guid id)
### Managing Resource Permissions
Once you have defined resource permissions, you need a way to grant or revoke them for specific users, roles, or clients. ABP provides two approaches for managing resource permissions: through built-in **UI components** that offer a user-friendly interface, or **programmatically** using the `IResourcePermissionManager` service for automated scenarios.
#### Resource Permission Management Modal
ABP provides built-in UI components for managing resource permissions on all supported UI frameworks (**MVC/Razor Pages**, **Blazor** and **Angular** UIs) as explained in the following sections.
##### MVC / Razor Pages
You can use the `abp.ModalManager` to open the resource permission management dialog as follows:
```javascript
var _resourcePermissionsModal = new abp.ModalManager(
abp.appPath + 'AbpPermissionManagement/ResourcePermissionManagementModal'
);
// Open the modal for a specific resource
_resourcePermissionsModal.open({
resourceName: 'BookStore.Document',
resourceKey: documentId,
resourceDisplayName: documentTitle
});
```
##### Blazor
You can use the `ResourcePermissionManagementModal` component in Blazor UI and open the resource management modal by using the `OpenAsync` method:
```xml
<ResourcePermissionManagementModal @ref="ResourcePermissionModal" />
@code {
private ResourcePermissionManagementModal ResourcePermissionModal { get; set; }
private async Task OpenPermissionsModal(DocumentDto document)
{
await ResourcePermissionModal.OpenAsync(
resourceName: "BookStore.Document",
resourceKey: document.Id.ToString(),
resourceDisplayName: document.Title
);
}
}
```
##### Angular
For Angular UI, you can use the `ResourcePermissionManagementComponent` as follows:
```typescript
import { ResourcePermissionManagementComponent } from '@abp/ng.permission-management';
// In your component
openPermissionsModal(document: DocumentDto) {
const modalRef = this.modalService.open(ResourcePermissionManagementComponent, {
// modal options
});
modalRef.componentInstance.resourceName = 'BookStore.Document';
modalRef.componentInstance.resourceKey = document.id;
modalRef.componentInstance.resourceDisplayName = document.title;
}
```
#### Using `IResourcePermissionManager`
For programmatic permission management, you can use the `IResourcePermissionManager` service for getting/setting permissions for resources:
```csharp
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.PermissionManagement;
namespace Acme.BookStore.Documents
{
public class DocumentPermissionService : ITransientDependency
{
private readonly IResourcePermissionManager _resourcePermissionManager;
public DocumentPermissionService(
IResourcePermissionManager resourcePermissionManager)
{
_resourcePermissionManager = resourcePermissionManager;
}
public async Task GrantViewPermissionToUserAsync(
Guid documentId,
Guid userId)
{
await _resourcePermissionManager.SetAsync(
permissionName: "BookStore_Document_View",
resourceName: "BookStore.Document",
resourceKey: documentId.ToString(),
providerName: "U", // User provider
providerKey: userId.ToString(),
isGranted: true
);
}
public async Task GrantEditPermissionToRoleAsync(
Guid documentId,
string roleName)
{
await _resourcePermissionManager.SetAsync(
permissionName: "BookStore_Document_Edit",
resourceName: "BookStore.Document",
resourceKey: documentId.ToString(),
providerName: "R", // Role provider
providerKey: roleName,
isGranted: true
);
}
public async Task RevokeAllPermissionsForUserAsync(
Guid documentId,
Guid userId)
{
await _resourcePermissionManager.DeleteAsync(
resourceName: "BookStore.Document",
resourceKey: documentId.ToString(),
providerName: "U",
providerKey: userId.ToString()
);
}
}
}
```
The `IResourcePermissionManager` service allows you to programmatically grant, revoke, and query resource permissions at runtime. This is useful for scenarios like automatically granting permissions when a resource is created, implementing sharing functionality, or integrating with external systems.
> *Note:* When using the built-in UI components (Resource Permission Management Modal), the permission management for users, roles, and clients is automatically handled through the interface without requiring any additional code.
## Integration with Entities
ABP entities automatically implement the `IKeyedObject` interface, which is used by the resource-based authorization system:
Once you have defined resource permissions, you need a way to grant or revoke them for specific users, roles, or clients. The [Permission Management Module](../../../modules/permission-management.md) provides the infrastructure for managing resource permissions:
```csharp
public interface IKeyedObject
{
string? GetObjectKey();
}
```
For entities with a primary key, `GetObjectKey()` returns the key as a string. This enables convenient extension methods on `IResourcePermissionChecker`:
```csharp
// Instead of this:
await _resourcePermissionChecker.IsGrantedAsync(
"BookStore_Document_View",
"BookStore.Document",
document.Id.ToString());
// You can write:
await _resourcePermissionChecker.IsGrantedAsync(
"BookStore_Document_View",
document);
```
> See the [Entities documentation](../../architecture/domain-driven-design/entities.md) for more information about the `IKeyedObject` interface.
## Advanced Topics
### Custom Resource Permission Value Providers
Similar to the standard permission system, you can create custom value providers for resource permissions.
ABP comes with two built-in resource permission value providers:
* `UserResourcePermissionValueProvider` (`U`): Checks permissions granted directly to users
* `RoleResourcePermissionValueProvider` (`R`): Checks permissions granted to roles
You can create your own custom value provider by implementing the `IResourcePermissionValueProvider` interface or inheriting from the `ResourcePermissionValueProvider` base class:
```csharp
using System.Threading.Tasks;
using Volo.Abp.Authorization.Permissions.Resources;
public class OwnerResourcePermissionValueProvider : ResourcePermissionValueProvider
{
public override string Name => "Owner";
public OwnerResourcePermissionValueProvider(
IResourcePermissionStore permissionStore)
: base(permissionStore)
{
}
public override async Task<PermissionGrantResult> CheckAsync(
ResourcePermissionValueCheckContext context)
{
// Check if the current user is the owner of the resource
var currentUserId = context.Principal?.FindUserId();
if (currentUserId == null)
{
return PermissionGrantResult.Undefined;
}
// Your logic to determine if user is the owner
var isOwner = await CheckIfUserIsOwnerAsync(
currentUserId.Value,
context.ResourceName,
context.ResourceKey);
return isOwner
? PermissionGrantResult.Granted
: PermissionGrantResult.Undefined;
}
private Task<bool> CheckIfUserIsOwnerAsync(
Guid userId,
string resourceName,
string resourceKey)
{
// Implement your ownership check logic
throw new NotImplementedException();
}
}
```
Register your custom provider in your module's `ConfigureServices` method:
```csharp
Configure<AbpPermissionOptions>(options =>
{
options.ResourceValueProviders.Add<OwnerResourcePermissionValueProvider>();
});
```
### Resource Permission Store
The `IResourcePermissionStore` interface is responsible for retrieving resource permission values. The [Permission Management Module](../../../modules/permission-management.md) provides the default implementation that stores permissions in the database.
You can query the store directly if needed:
```csharp
public class MyService : ITransientDependency
{
private readonly IResourcePermissionStore _resourcePermissionStore;
public MyService(IResourcePermissionStore resourcePermissionStore)
{
_resourcePermissionStore = resourcePermissionStore;
}
public async Task<string[]> GetGrantedResourceKeysAsync(string permissionName)
{
// Get all resource keys where the permission is granted
return await _resourcePermissionStore.GetGrantedResourceKeysAsync(
"BookStore.Document",
permissionName);
}
}
```
### Cleaning Up Resource Permissions
When a resource is deleted, you should clean up its associated permissions to avoid orphaned permission records in the database. You can do this directly in your delete logic or handle it asynchronously through event handlers:
```csharp
public async Task DeleteDocumentAsync(Guid id)
{
// Delete the document
await _documentRepository.DeleteAsync(id);
// Clean up all permissions for this resource
await _resourcePermissionManager.DeleteAsync(
resourceName: "BookStore.Document",
resourceKey: id.ToString(),
providerName: "U",
providerKey: null // Deletes for all users
);
await _resourcePermissionManager.DeleteAsync(
resourceName: "BookStore.Document",
resourceKey: id.ToString(),
providerName: "R",
providerKey: null // Deletes for all roles
);
}
```
- **UI Components**: Built-in modal dialogs for managing resource permissions on all supported UI frameworks (MVC/Razor Pages, Blazor, and Angular). These components allow administrators to grant or revoke permissions for users and roles on specific resource instances through a user-friendly interface.
- **`IResourcePermissionManager` Service**: A service for programmatically granting, revoking, and querying resource permissions at runtime. This is useful for scenarios like automatically granting permissions when a resource is created, implementing sharing functionality, or integrating with external systems.
> ABP modules automatically handle permission cleanup for their own entities. For your custom entities, you are responsible for cleaning up resource permissions when resources are deleted.
> See the [Permission Management Module](../../../modules/permission-management.md#resource-permission-management-dialog) documentation for detailed information on using the UI components and the `IResourcePermissionManager` service.
## See Also
* [Authorization](./index.md)
* [Permission Management Module](../../modules/permission-management.md)
* [Permission Management Module](../../../modules/permission-management.md)
* [Entities](../../architecture/domain-driven-design/entities.md)

BIN
docs/en/images/resource-based-permission.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

303
docs/en/modules/permission-management.md

@ -7,7 +7,7 @@
# Permission Management Module
This module implements the `IPermissionStore` to store and manage permissions values in a database.
This module implements the `IPermissionStore` and `IResourcePermissionStore` to store and manage permission values in a database.
> This document covers only the permission management module which persists permission values to a database. See the [Authorization document](../framework/fundamentals/authorization/index.md) to understand the authorization and permission systems.
@ -33,9 +33,85 @@ When you click *Actions* -> *Permissions* for a role, the permission management
In this dialog, you can grant permissions for the selected role. The tabs in the left side represents main permission groups and the right side contains the permissions defined in the selected group.
### Resource Permission Management Dialog
In addition to standard permissions, this module provides a reusable dialog for managing **resource-based permissions** on specific resource instances. This allows administrators to grant or revoke permissions for users, roles and clients on individual resources (e.g., a specific document, project, or any entity).
![resource-permissions-module-dialog](../images/resource-based-permission.gif)
The dialog displays all resource permissions defined for the resource type and allows granting them to specific users, roles or clients for the selected resource instance.
You can integrate this dialog into your own application to manage permissions for your custom entities and resources. See the following sections to learn how to use the component in each UI framework.
#### MVC / Razor Pages
Use the `abp.ModalManager` to open the resource permission management dialog:
````javascript
var _resourcePermissionsModal = new abp.ModalManager(
abp.appPath + 'AbpPermissionManagement/ResourcePermissionManagementModal'
);
// Open the modal for a specific resource
_resourcePermissionsModal.open({
resourceName: 'MyApp.Document',
resourceKey: documentId,
resourceDisplayName: documentTitle
});
````
#### Blazor
Use the `ResourcePermissionManagementModal` component's `OpenAsync` method to open the dialog:
````razor
@using Volo.Abp.PermissionManagement.Blazor.Components
<ResourcePermissionManagementModal @ref="ResourcePermissionModal" />
@code {
private ResourcePermissionManagementModal ResourcePermissionModal { get; set; }
private async Task OpenPermissionsModal()
{
await ResourcePermissionModal.OpenAsync(
resourceName: "MyApp.Document",
resourceKey: Document.Id.ToString(),
resourceDisplayName: Document.Title
);
}
}
````
#### Angular
Use the `ResourcePermissionManagementComponent`:
````typescript
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { ResourcePermissionManagementComponent } from '@abp/ng.permission-management';
@Component({
// ...
})
export class DocumentListComponent {
constructor(private modalService: NgbModal) {}
openPermissionsModal(document: DocumentDto) {
const modalRef = this.modalService.open(
ResourcePermissionManagementComponent,
{ size: 'lg' }
);
modalRef.componentInstance.resourceName = 'MyApp.Document';
modalRef.componentInstance.resourceKey = document.id;
modalRef.componentInstance.resourceDisplayName = document.title;
}
}
````
## IPermissionManager
`IPermissionManager` is the main service provided by this module. It is used to read and change the permission values. `IPermissionManager` is typically used by the *Permission Management Dialog*. However, you can inject it if you need to set a permission value.
`IPermissionManager` is the main service provided by this module. It is used to read and change the global permission values. `IPermissionManager` is typically used by the *Permission Management Dialog*. However, you can inject it if you need to set a permission value.
> If you just want to read/check permission values for the current user, use the `IAuthorizationService` or the `[Authorize]` attribute as explained in the [Authorization document](../framework/fundamentals/authorization/index.md).
@ -67,9 +143,125 @@ public class MyService : ITransientDependency
}
````
## IResourcePermissionManager
`IResourcePermissionManager` is the service for programmatically managing resource-based permissions. It is typically used by the *Resource Permission Management Dialog*. However, you can inject it when you need to grant, revoke, or query permissions for specific resource instances.
> If you just want to check resource permission values for the current user, use the `IResourcePermissionChecker` service as explained in the [Resource-Based Authorization](../framework/fundamentals/authorization/resource-based-authorization.md) document.
**Example: Grant and revoke resource permissions programmatically**
````csharp
public class DocumentPermissionService : ITransientDependency
{
private readonly IResourcePermissionManager _resourcePermissionManager;
public DocumentPermissionService(
IResourcePermissionManager resourcePermissionManager)
{
_resourcePermissionManager = resourcePermissionManager;
}
public async Task GrantViewPermissionToUserAsync(
Guid documentId,
Guid userId)
{
await _resourcePermissionManager.SetAsync(
permissionName: "MyApp_Document_View",
resourceName: "MyApp.Document",
resourceKey: documentId.ToString(),
providerName: "U", // User
providerKey: userId.ToString(),
isGranted: true
);
}
public async Task GrantEditPermissionToRoleAsync(
Guid documentId,
string roleName)
{
await _resourcePermissionManager.SetAsync(
permissionName: "MyApp_Document_Edit",
resourceName: "MyApp.Document",
resourceKey: documentId.ToString(),
providerName: "R", // Role
providerKey: roleName,
isGranted: true
);
}
public async Task RevokeUserPermissionsAsync(
Guid documentId,
Guid userId)
{
await _resourcePermissionManager.DeleteAsync(
resourceName: "MyApp.Document",
resourceKey: documentId.ToString(),
providerName: "U",
providerKey: userId.ToString()
);
}
}
````
## IResourcePermissionStore
The `IResourcePermissionStore` interface is responsible for retrieving resource permission values from the database. This module provides the default implementation that stores permissions in the database.
You can query the store directly if needed:
````csharp
public class MyService : ITransientDependency
{
private readonly IResourcePermissionStore _resourcePermissionStore;
public MyService(IResourcePermissionStore resourcePermissionStore)
{
_resourcePermissionStore = resourcePermissionStore;
}
public async Task<string[]> GetGrantedResourceKeysAsync(string permissionName)
{
// Get all resource keys where the permission is granted
return await _resourcePermissionStore.GetGrantedResourceKeysAsync(
"MyApp.Document",
permissionName);
}
}
````
## Cleaning Up Resource Permissions
When a resource is deleted, you should clean up its associated permissions to avoid orphaned permission records in the database. You can do this directly in your delete logic or handle it asynchronously through event handlers:
````csharp
public async Task DeleteDocumentAsync(Guid id)
{
// Delete the document
await _documentRepository.DeleteAsync(id);
// Clean up all permissions for this resource
await _resourcePermissionManager.DeleteAsync(
resourceName: "MyApp.Document",
resourceKey: id.ToString(),
providerName: "U",
providerKey: null // Deletes for all users
);
await _resourcePermissionManager.DeleteAsync(
resourceName: "MyApp.Document",
resourceKey: id.ToString(),
providerName: "R",
providerKey: null // Deletes for all roles
);
}
````
> ABP modules automatically handle permission cleanup for their own entities. For your custom entities, you are responsible for cleaning up resource permissions when resources are deleted.
## Permission Management Providers
Permission Management Module is extensible, just like the [permission system](../framework/fundamentals/authorization/index.md). You can extend it by defining permission management providers.
Permission Management Module is extensible, just like the [permission system](../framework/fundamentals/authorization/index.md). You can extend it by defining permission management providers.
[Identity Module](identity.md) defines the following permission management providers:
@ -111,6 +303,109 @@ Configure<PermissionManagementOptions>(options =>
The order of the providers are important. Providers are executed in the reverse order. That means the `CustomPermissionManagementProvider` is executed first for this example. You can insert your provider in any order in the `Providers` list.
### Resource Permission Management Providers
Similar to standard permission management providers, you can create custom providers for resource permissions by implementing `IResourcePermissionManagementProvider` or inheriting from `ResourcePermissionManagementProvider`:
````csharp
public class CustomResourcePermissionManagementProvider
: ResourcePermissionManagementProvider
{
public override string Name => "Custom";
public CustomResourcePermissionManagementProvider(
IResourcePermissionGrantRepository resourcePermissionGrantRepository,
IGuidGenerator guidGenerator,
ICurrentTenant currentTenant)
: base(
resourcePermissionGrantRepository,
guidGenerator,
currentTenant)
{
}
}
````
After creating the custom provider, you need to register your provider using the `PermissionManagementOptions` in your module class:
````csharp
Configure<PermissionManagementOptions>(options =>
{
options.ResourceManagementProviders.Add<CustomResourcePermissionManagementProvider>();
});
````
## Permission Value Providers
Permission value providers are used to determine if a permission is granted. They are different from management providers: **value providers** are used when *checking* permissions, while **management providers** are used when *setting* permissions.
> For standard permissions, see the [Authorization document](../framework/fundamentals/authorization/index.md) for details on permission value providers.
### Resource Permission Value Providers
Similar to the standard permission system, you can create custom value providers for resource permissions. ABP comes with two built-in resource permission value providers:
* `UserResourcePermissionValueProvider` (`U`): Checks permissions granted directly to users
* `RoleResourcePermissionValueProvider` (`R`): Checks permissions granted to roles
You can create your own custom value provider by implementing the `IResourcePermissionValueProvider` interface or inheriting from the `ResourcePermissionValueProvider` base class:
````csharp
using System.Threading.Tasks;
using Volo.Abp.Authorization.Permissions.Resources;
public class OwnerResourcePermissionValueProvider : ResourcePermissionValueProvider
{
public override string Name => "Owner";
public OwnerResourcePermissionValueProvider(
IResourcePermissionStore permissionStore)
: base(permissionStore)
{
}
public override async Task<PermissionGrantResult> CheckAsync(
ResourcePermissionValueCheckContext context)
{
// Check if the current user is the owner of the resource
var currentUserId = context.Principal?.FindUserId();
if (currentUserId == null)
{
return PermissionGrantResult.Undefined;
}
// Your logic to determine if user is the owner
var isOwner = await CheckIfUserIsOwnerAsync(
currentUserId.Value,
context.ResourceName,
context.ResourceKey);
return isOwner
? PermissionGrantResult.Granted
: PermissionGrantResult.Undefined;
}
private Task<bool> CheckIfUserIsOwnerAsync(
Guid userId,
string resourceName,
string resourceKey)
{
// Implement your ownership check logic
throw new NotImplementedException();
}
}
````
Register your custom provider in your module's `ConfigureServices` method:
````csharp
Configure<AbpPermissionOptions>(options =>
{
options.ResourceValueProviders.Add<OwnerResourcePermissionValueProvider>();
});
````
## See Also
* [Authorization](../framework/fundamentals/authorization/index.md)
* [Authorization](../framework/fundamentals/authorization/index.md)
* [Resource-Based Authorization](../framework/fundamentals/authorization/resource-based-authorization.md)

Loading…
Cancel
Save