abp icon indicating copy to clipboard operation
abp copied to clipboard

Resource based authorization

Open maliming opened this issue 1 month ago • 0 comments

Resolves #236

Demo: https://github.com/maliming/AbpResourcePermission

Work to be done

  • [x] Implement IResourcePermissionChecker in the Permission Management module. This is just for checking permissions, not managing (setting) them. Defined in the framework, so any module can be independent of the Permission Management module, yet can check permissions. We can implement as NullResourcePermissionChecker (just throw not implemented exception for now) in the framework to not get DI exceptions.
  • [x] Create IResourcePermissionManager to manage (get/set) permissions for resources in the Permission Management module, like the current IPermissionManager service. Implement it in the same place.
  • [x] Create an app service to provide application logic to manage resource permissions.
  • [x] Define a resource permission management modal, which should be reusable, like the current permission management modal.

Demo

https://github.com/maliming/AbpResourcePermission/commit/7cb3269db0c5fb563994f0898ede68c6c3691163

Define resource permissions:

public class BookStorePermissionDefinitionProvider : PermissionDefinitionProvider
{
    public override void Define(IPermissionDefinitionContext context)
    {
        AddBookStoreResourcePermission(context);
    }

    protected virtual void AddBookStoreResourcePermission(IPermissionDefinitionContext context)
    {
        var bookStoreGroup = context.GetGroup(BookStorePermissions.GroupName);

        bookStoreGroup.AddPermission(BookStorePermissions.Resources.ManageChangeBookName, L("Manage change book name"));
        context.AddResourcePermission(BookStorePermissions.Resources.ChangeBookName,
            BookStorePermissions.Resources.BookResourceName,
            BookStorePermissions.Resources.ManageChangeBookName,
            L("Change book name"));

        bookStoreGroup.AddPermission(BookStorePermissions.Resources.ManageChangeBookType, L("Manage change book type"));
        context.AddResourcePermission(BookStorePermissions.Resources.ChangeBookPrice,
            BookStorePermissions.Resources.BookResourceName,
            BookStorePermissions.Resources.ManageChangeBookType,
            L("Change book type"));

        bookStoreGroup.AddPermission(BookStorePermissions.Resources.ManageChangeBookPrice, L("Manage change book price"));
        context.AddResourcePermission(BookStorePermissions.Resources.ChangeBookType,
            BookStorePermissions.Resources.BookResourceName,
            BookStorePermissions.Resources.ManageChangeBookPrice,
            L("Change book price"));
    }

    private static LocalizableString L(string name)
    {
        return LocalizableString.Create<BookStoreResource>(name);
    }
}

Implement IHasResourcePermissions in DTO class

public class BookDto : AuditedEntityDto<Guid>, IHasResourcePermissions
{
    public string Name { get; set; }

    //...

    public Dictionary<string, bool> ResourcePermissions { get; set; }
}

Use ResourcePermissionPopulator to populate the resource permissions:

public override async Task<BookDto> GetAsync(Guid id)
{
    //...
    var bookDto = ObjectMapper.Map<Book, BookDto>(queryResult.book);

    await _resourcePermissionPopulator.PopulateAsync(bookDto, typeof(Book).FullName!);

    return bookDto;
}

public override async Task<PagedResultDto<BookDto>> GetListAsync(PagedAndSortedResultRequestDto input)
{
    //...
    var bookDtos = queryResult.Select(x =>
    {
        var bookDto = ObjectMapper.Map<Book, BookDto>(x.book);
        bookDto.AuthorName = x.author.Name;
        return bookDto;
    }).ToList();

    await _resourcePermissionPopulator.PopulateAsync(bookDtos, typeof(Book).FullName!);

    return new PagedResultDto<BookDto>(totalCount, bookDtos);
}

Use IAuthorizationService to check resource permissions in the backend app:

var books = await BookRepository.GetListAsync();
var resourvePermissions = new Dictionary<string, bool>();
foreach (var book in books)
{
    resourvePermissions[book.Name] = await AuthorizationService.IsGrantedAsync(book, BookStorePermissions.Resources.ChangeBookName);
}

Screenshots:

image image image image

maliming avatar Nov 15 '25 05:11 maliming