abp
abp copied to clipboard
Resource based authorization
Resolves #236
Demo: https://github.com/maliming/AbpResourcePermission
Work to be done
- [x] Implement
IResourcePermissionCheckerin 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
IResourcePermissionManagerto 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: