-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dynamic permissions #13644
Dynamic permissions #13644
Conversation
This is a breaking change and I will create a separate issue to explain it.
for storage optimization when we want to store that type of data.
…f global feature requirements.
@maliming you are the main reviewer of this PR. I assigned others to inform them what's happing. |
From the global application name.
BTW, I've created a branch for manual testing: https://github.com/abpframework/abp/tree/dynamic-permissions-test-app-template-never-merge |
setting manage and menu manage same problem @hikalkan |
setting is done: #16945 |
localization has the same problem @hikalkan |
The Problem
When we create a microservice system, we will have many microservices. Every microservice will define their permissions in their
Application.Contratcs
packages. We also have a permission management dialog to assign permissions to users/roles. In this dialog, we need all the permissions. Also, when a user logins, we get all the granted permissions for this user to be able to render the user interface (many items on UI depends on granted permissions, like toolbars, main menu items, etc). Asking permission grants or definitions to individual microservices would be very inefficient (even if you cache every possible thing and make a complex system).Until now, we were solving the issue by adding an administration microservice to the solution. This administration microservice has project/package reference to
Application.Contratcs
packages of all other microservices. In this way, it can know all the permission definitions in the system. So, it can return a list of all permission definitions and also easily check all permission grants of a specific user in a single service.However, this design makes administration microservice depending on all other service. Whenever we deploy a new version of Microservice X, we need to re-deploy the administration service. Otherwise, it can't have knowledge of newly defined permission in the Microservice X, and we can't see the new permissions while authorizing roles/users in the admin side, or getting all granted permissions of a user.
The Solution
The solution in this PR introduces dynamic permission store;
PermissionDefinition
objects in-memory (all the dynamic permissions are stored in the memory). In this way, it knows all the permissions in the system. This is also well optimized. Permissions are read only once in service startup (in a separate thread) and read again only if another microservice has changed permissions.While the solution is simple and straightforward, I made a lot of changes to make this solution working with the ABP Framework and current Permission Management module.
What's Done in This PR, in More Details
PermissionGroupDefinitionRecord
andPermissionDefinitionRecord
entities in the Permission Management module, to save permission definitions in the database.AbpPermissionManagementDomainModule
). Also, reading permission definitions from database. In this way, different applications may save permissions in the same database, and one of this applications can be used to get all permissions and authorize users in the UI.ISimpleStateCheckerSerializer
andISimpleStateCheckerSerializerContributor
interfaces). I implemented the contributor for all state checkers in the framework. If you have custom state checkers, you can write your own contributors and register to DI, that's all.IDynamicPermissionDefinitionStore
to allow us to get permission definitions dynamically. Also introducedIStaticPermissionDefinitionStore
that gets permission definitions as before.IPermissionDefinitionManager
now uses both of these.PermissionChecker
returnsfalse
(prohibited) for undefined permissions.IRootServiceProviderAccessor
as a new feature. It is used to get the service provider from the root scope, which won't be disposed.LocalizableString
now fallbacks to the default localization resource if it can't localize in the given resource, or the resource was not given.ILocalizableStringSerializer
to serialize anILocalizableString
to astring
and vice verse. I used this to while serializing permission definitions (for their localizable display names).IHasExtraProperties.HasSameExtraProperties
andExtraPropertyDictionary.HasSameItems
for some comparison purposes.DisplayNameKey
andDisplayNameResource
in thePermissionGrantInfo
DTO class. In this way, UI layer can localize the display name in the UI side.DisplayName
is preserved to be backward-compatible, but may not be truly set in the application layer if the related localization resource is not available in the application that hosts the permission management application service. So, I updated localizations in MVC and Blazor UIs. It should also be done in Angular too (I will organize this).AbpApplicationCreationOptions
). Then, when we need it, we can injectIApplicationNameAccessor
. If we need it before the dependency injection system is ready, we can get it from theIServiceCollection.GetApplicationName()
extension method (for example in theConfigureServices
method of our module. Application name isnull
if not configured. If you have a monolith application, you mostly don't need to care about it. In a microservice system, it can be set to microservice's name.AbpAuditingOptions.ApplicationName
from the new Application Name by default.Breaking Changes
IPermissionDefinitionManager
methods are converted to asynchronous, and renamed (addedAsync
postfix).MultiTenancySides
from permission groups.MultiTenancySides
enum frombyte
(default wasint
).