A Preliminary Study on the permission design and a preliminary study on the permission Design
For large and small projects, we need to design permissions. We all want to design a general permission and make the permissions more complex. Now we have understood the design concept of the relevant project and think the design is very simple, however, the implementation methods and ideas are intriguing.
This article only introduces the database design of AbpPermissions. For other table structures, refer to the source code for [Name (unique Id of the resource file)] and [IsGranted (whether to authorize)]., [RoleId, UserId (authorized to a role or user)]
All the constant data of the ABP is passed when the program is started.AbpKernelModuleOne-time loading is completed, and can be directly read from the memory when used
Public override void PostInitialize () {RegisterMissingComponents (); IocManager. resolve <LocalizationManager> (). initialize (); // Initialize the resource file IocManager. resolve <NavigationManager> (). initialize (); // Initialize the IocManager permission. resolve <PermissionManager> (). initialize (); // Initialize IocManager. resolve <SettingDefinitionManager> (). initialize ();}
Permissions can be divided into front-end permission judgment and back-end permission judgment. JS judges permissions by referencing <script src = "~ /AbpScripts/GetScripts "type =" text/javascript "> </script> This script loads the relevant JS objects and methods to the JS file.
There are two red boxes in the left-side Navigation Pane. The MainMenu is the default property of the system, and the Test is the custom property. The following code
Public class authorization: NavigationProvider {public override void SetNavigation (INavigationProviderContext context) {SetNavigation1 (context); SetTestNavigation (context);} private void SetNavigation1 (INavigationProviderContext context) {context. manager. mainMenu // default navigation property. addItem (new MenuItemDefinition ("Questions", new LocalizableString ("Questions", ModuleZeroSampleProjectConsts. localizationSourceName), url: "#/questions", icon: "fa-question", requiredPermissionName: "Questions" // determine permissions based on variables )). addItem (new MenuItemDefinition ("Users", new LocalizableString ("Users", ModuleZeroSampleProjectConsts. localizationSourceName), url: "#/users", icon: "fa-users");} public const string TestName = "Test "; // custom navigation attribute private void SetTestNavigation (INavigationProviderContext context) {var testMenu = new MenuDefinition (TestName, new FixedLocalizableString ("Frontend menu"); context. manager. menus [TestName] = testMenu; testMenu. addItem (new MenuItemDefinition ("Questions", new LocalizableString ("Questions", ModuleZeroSampleProjectConsts. localizationSourceName), url: "#/questions", icon: "fa-question ")). addItem (new MenuItemDefinition ("Users", new LocalizableString ("Users", ModuleZeroSampleProjectConsts. localizationSourceName), url: "#/users", icon: "fa-users "));}}View Code
The JS Code is loaded by GetScriptAsync () of the NavigationScriptManager class, and the permission is judged. The obtained navigation data is obtained through the abp. nav. menus. MainMenu
Public async Task <IReadOnlyList <UserMenu> GetMenusAsync (long? UserId) // load the relevant navigation {var userMenus = new List <UserMenu> (); foreach (var menu in _ navigationManager. menus. values) // all navigation attributes initialized by default {userMenus. add (await GetMenuAsync (menu. name, userId);} return userMenus;} private async Task <int> FillUserMenuItems (long? UserId, IList <dimension> menuItemDefinitions, IList <UserMenuItem> userMenuItems) {var dimensions = 0; foreach (var values in menuItemDefinitions) {if (MenuItemDefinition. RequiresAuthentication &&! UserId. HasValue) {continue;} if (! String. IsNullOrEmpty (menuItemDefinition. RequiredPermissionName )&&(! UserId. HasValue |! (Await PermissionChecker. isGrantedAsync (userId. value, menuItemDefinition. requiredPermissionName) // determines whether the current user has the navigation permission {continue;} var userMenuItem = new UserMenuItem (menuItemDefinition) based on the current user ID and permission. if (menuItemDefinition. isLeaf | (await FillUserMenuItems (userId, menuItemDefinition. items, userMenuItem. items)> 0) // recursively load the hierarchical navigation {userMenuItems. add (userMenuItem); ++ addedMenuItemCount;} return addedMenuItemCount ;}View Code
Abp. js defines many methods and attributes, and the user judges the permission to be an ABC. auth. hasPermission (). The parameter of this method is the operation permission corresponding to the background Action. If the return value of this method is True, the current user is granted the permission.
Front-end JS loads all permissions and current user permissions through the GetScript method of the AuthorizationScriptManager class
Public async Task <string> GetScriptAsync () {var allPermissionNames = _ permissionManager. getAllPermissions (false ). select (p => p. name ). toList (); // get all permissions var grantedPermissionNames = new List <string> (); if (AbpSession. userId. hasValue) {foreach (var permissionName in allPermissionNames) {if (await PermissionChecker. isGrantedAsync (AbpSession. userId. value, permissionName) {grantedPermissionNames. add (permissionName); // obtain the permissions of the current user }}var script = new StringBuilder (); script. appendLine ("(function () {"); script. appendLine (); script. appendLine ("abp. auth = abp. auth | {}; "); script. appendLine (); AppendPermissionList (script, "allPermissions", allPermissionNames); script. appendLine (); AppendPermissionList (script, "grantedPermissions", grantedPermissionNames); script. appendLine (); script. append ("}) ();"); return script. toString ();}View Code
Permission initialization definition must be integrated with AuthorizationProvider, as shown below:
Public class ModuleZeroSampleProjectAuthorizationProvider: AuthorizationProvider {public override void SetPermissions (IPermissionDefinitionContext context) {// TODO: Localize (Change FixedLocalizableString to LocalizableString) context. createPermission ("CanCreateQuestions", new FixedLocalizableString ("Can create questions"); context. createPermission ("CanDeleteQuestions", new FixedLocalizableString ("Can delete questions"); context. createPermission ("CanDeleteAnswers", new FixedLocalizableString ("Can delete answers"); context. createPermission ("CanAnswerToQuestions", new FixedLocalizableString ("Can answer to questions"), isGrantedByDefault: true );}}View Code
All permission verification is completed through AbpUserManager. The following are several important methods:
Task <bool> IsGrantedAsync (long userId, string permissionName)
(Await UserPermissionStore. HasPermissionAsync (user, new PermissionGrantInfo (permission. Name, false) checks whether the current user is granted Permissions
Take QuestionAppService as an example to describe the permission configuration. For each Service layer, set the permission [AbpAuthorize ("Questions")]. When a request is sent, the interceptor automatically verifies the permission, each Action also intercepts [AbpAuthorize ("CanCreateQuestions")]. Permission interception is implemented by AuthorizationInterceptor.
Permission verification is performed using the following methods:
Internal class AuthorizeAttributeHelper: IAuthorizeAttributeHelper, ITransientDependency {public async Task AuthorizeAsync (IEnumerable <IAbpAuthorizeAttribute> authorizeAttributes) {if (! AbpSession. UserId. HasValue) {throw new AbpAuthorizationException ("No user logged in! ");} Foreach (var authorizeAttribute in authorizeAttributes) {await PermissionChecker. AuthorizeAsync (authorizeAttribute. RequireAllPermissions, authorizeAttribute. Permissions); // permission check }}}View Code
It is recommended that you first learn how to use the source code, debug it during use, and gradually become familiar with the source code. It is really difficult to directly study the source code without using it, as the saying goes, "Practice makes perfect" should mean this. The technical level and ability of each person are different. The suggestion is just my personal opinion.