HZERO Micro Service Platform 11: Data Permissions for Code Analysis, sql Interception.md

Table/Entity Relationships

Menu: [Data Permission Rules], [Document Permissions]
The relationship between the two: [Document Permission] Based on the Data Permission Rules, in order to facilitate re-encapsulation, the Create Document Permission actually automatically maintains several tables related to the Data Permission Rules;

[Data Permission Rules]

  • hpfm_permission_range Data Shield Range
    • The scope of the rule's role, which can be limited to tables, services, sqlid, tenants
  • hpfm_permission_rule shielding rules
    • Existing rules: 1. Prefix tables; 2. Document rights automatically generated
  • hpfm_permission_rel shielding range rule relation
    • Intermediate table of range and rule
  • hpfm_permission_range_excl blocking range blacklist
    • No data now

[Document Rights]

  • hiam_role_auth_data Role Document Rights Management
    • Includes: Roles, Document Rights Encoding
  • hiam_role_auth_data_line
    • Includes: header id,data_id

Data Source: [Role Management] - [Maintain Data Permissions]

  • Hiam_ Role_ Auth_ Source of data
  • Hiam_ Role_ Auth_ Data_ Sources of line, such as menu permissions, add label_when data is added ID inserted into hiam_role_auth_data_line.data_id;

Data Rights Implementation Process

principle

To assign functional privileges is to add and add privileges to users. Assigning data permissions is a subtraction that reduces the amount of data that users can access and usually adds filtering conditions to sql.
For example, query users:

select * from iam_user as user where .....

Restrict users who can only query Department 1:

select * from (select * from iam_user where dept_id = 1) as user where .....

Put table name iam_user replaced with iam_user's subquery restricts users who can only query Department 1 without affecting other parts of sql;

mybatis preprocesses SQL before executing sql, replacing table names with subqueries according to some rules; If rules can be maintained dynamically, dynamic data rights control can be achieved.

Code Flow

Interrupt PermissionSqlBuilder#getPermissionRange;

org.apache.ibatis.plugin.Interceptor //Plug-in mechanism for ibatis
org.hzero.mybatis.parser.SqlParserInterceptor#intercept
statement = sqlInterceptor.handleStatement(statement....
SqlInterceptor#handleStatement
SqlInterceptor#handlePlainSelect
FromItem afterHandlerFromItem = handleTable((Table) fromItem, serviceName, sqlId, args, userDetails);
PermissionSqlBuilder#handleTable
PermissionSqlBuilder#handleTable2FromItem
PermissionSqlBuilder#getPermissionRange //permissionRange is the key
PermissionRangeVO permissionRange = this.permissionSqlRepository.getPermissionRange(serviceName, table, sqlId, userDetails.getTenantId());
DefaultPermissionSqlRepository#getPermissionRange
Map<String, String> permissionRangeVOMap = redisHelper.hshGetAll(cacheKey); //Read from redis, initialization is done when the platform service starts;

DefaultPermissionSqlRepository#getPermissionRange:
The control rules for data permissions come from the hpfm:permission:{table name} of redis db1 (in this case, all tables of hzero cannot have the same name), where the "table name" is the table that needs to be controlled; For example, for iam_menu table for permission control, key is hpfm:permission:iam_menu; value value:

//PermissionRangeVO object
{"customRuleFlag":0,"sqlList":[],"dbPrefix":"","rangeExclList":[]}

The redis data is initialized from the time the platform service starts, (so if the redis data is deleted, the platform service needs to be restarted;)
Initialization method: org.hzero.platform.domain.entity.PermissionRange#initCache (found for the constructor breakpoint of PermissionRangeVO)

key point

  • sql is handed and footed in PermissionSqlBuilder
  • The control rules for data permissions come from: redis db1's hpfm:permission:{table name}, which is initialized when the platform service starts;
  • The sql that handles sql replacement table names comes from the enumeration class: DocTypeScript;

Key Classes

SqlInterceptor
org.hzero.mybatis.parser.SqlInterceptor

Rewrite the SQL in the Mybatis interceptor, and rewrite the part of the SQL you need to rewrite when you implement the interface

SqlParserInterceptor
sqlParser interceptor:

SqlParserInterceptor#sqlInterceptors: 
org.hzero.boot.customize.interceptor.CustomizeSQLInterceptor
org.hzero.boot.platform.data.permission.builder.PermissionSqlBuilder

Splicing replacement xml

xml from enumeration org.hzero.iam.infra.constant.DocTypeScript, DocTypeServiceImpl#createDocType of Iam gets xml and replaces the variable, and Iam calls platform to insert into hpfm_ Permission_ In the rule table;
Example:

<bind name="roleMergeIdList" value="@io.choerodon.core.oauth.DetailsHelper@getUserDetails().roleMergeIds()" /> 
<bind name="roleAuthHeader" value="@org.hzero.boot.platform.data.permission.util.DocRedisUtils@checkRoleAuthHeaderAssign(121684538047991808L, &quot;BIZ&quot;, roleMergeIdList)" /> 
<bind name="roleAuthLine" value="@org.hzero.boot.platform.data.permission.util.DocRedisUtils@checkRoleAuthLineAssign(121684538047991808L, &quot;BIZ&quot;, &quot;SYS_API_SERVICE&quot;, roleMergeIdList)" /> 
<bind name="userAuthAssign" value="@org.hzero.boot.platform.data.permission.util.DocRedisUtils@checkUserAuthAssign(tenantId, &quot;SYS_API_SERVICE&quot;, userId)" /> 
<choose> 
    <when test="!roleAuthHeader"> 
        1=2 
    </when> 
    <when test="!roleAuthLine"> 
         1=1 
     </when> 
     <when test="!userAuthAssign"> 
         (EXISTS ( 
              SELECT 1  
              FROM hiam_role_auth_data hrad  
              LEFT JOIN hiam_role_auth_data_line hradl ON hrad.auth_data_id = hradl.auth_data_id  
              WHERE hrad.tenant_id = #{tenantId}  
              AND hrad.role_id IN 
             <foreach collection="roleMergeIdList" open="(" separator="," item="roleMergeId" close=")">
                             #{roleMergeId}             
</foreach> 
              AND hrad.authority_type_code = 'SYS_API_SERVICE' 
              AND (hrad.include_all_flag = 1 OR hradl.data_id IN (SELECT hs.service_id FROM
 hadm_service hs
 where   ${tableAlias}.service_name = hs.service_code)))) 
     </when> 
     <when test="userAuthAssign"> 
        (EXISTS ( 
            SELECT 1  
            FROM hiam_user_authority hua1  
            LEFT JOIN hiam_user_authority_line hual1 ON hua1.authority_id = hual1.authority_id  
            WHERE hua1.tenant_id = #{tenantId} 
            AND hua1.user_id = #{userId} 
            AND hua1.authority_type_code = 'SYS_API_SERVICE'  
            AND (hua1.include_all_flag = 1 OR hual1.data_id IN (SELECT hs.service_id FROM
 hadm_service hs
 where   ${tableAlias}.service_name = hs.service_code)))) 
     </when> 
     <otherwise> 
        1=2 
     </otherwise> 
</choose> 

Instance: api interface permissions, menu permissions

Requirements:
1. When permission set adds permissions, only the interface of this system can be added;
2. System administrators can only see the menu of this system;

Steps for writing sql:

  • Identify tables to filter (target tables): api(IAM_PERMISSION), menu(IAM_MENU)
  • Determine the field of the table to be filtered: api.service_ Name, menu->label
  • Determine the range of values for a field (Value Set/Value Set View): hadm_service, iam_label
  • Determine hiam_role_auth_data_line.data_id field to be saved (Long only): hadm_service.service_id, iam_label.id
  • Write a sql fragment to find out the data hiam_corresponding to the current row of the target table Role_ Auth_ Data_ Line.data_ ID

Actual api sql

Put iam_ Replace permission with:

(
    SELECT
        *
    FROM
        iam_permission DST__0
    WHERE
        (
            EXISTS (
                SELECT
                    1
                FROM
                    hzero_platform.hiam_role_auth_data hrad
                LEFT JOIN hzero_platform.hiam_role_auth_data_line hradl ON hrad.auth_data_id = hradl.auth_data_id
                WHERE
                    hrad.tenant_id = 0
                AND hrad.role_id IN (91468303490486272)
                AND hrad.authority_type_code = 'SYS_API_SERVICE'
                AND (
                    hrad.include_all_flag = 1
                    OR hradl.data_id IN ( /*data_id Is the valueField of the value set view*/
                        SELECT
                            hs.service_id
                        FROM
                            hzero_admin.hadm_service hs
                        WHERE
                            DST__0.service_name = hs.service_code
                    )
                )
            )
        )
) ip

Actual menu sql

Put iam_ Replace menu with:

(
    SELECT
        *
    FROM
        iam_menu DST__0
    WHERE
        (
            EXISTS (
                SELECT
                    1
                FROM
                    hiam_role_auth_data hrad
                LEFT JOIN hiam_role_auth_data_line hradl ON hrad.auth_data_id = hradl.auth_data_id
                WHERE
                    hrad.tenant_id = 0
                AND hrad.role_id IN (83532216818352128)
                AND hrad.authority_type_code = 'SUBSYS_MENU'
                AND (
                    hrad.include_all_flag = 1
                    OR hradl.data_id IN ( /*data_id Is the valueField of the value set view*/
                        SELECT
                            hrl.label_id
                        FROM
                            hiam_label_rel hrl
                        WHERE
                            hrl.data_id = DST__0.id
                        AND hrl.data_type = 'MENU'
                    )
                )
            )
        )
) im

Ideas for troubleshooting problems

Possible problems:

  • There are bug s in Data permission update, business scope, permission data and so on need to try several times to produce results;
  • Document permissions are disabled, but data permissions are controlled. 1=2 is generated in sql

Ideas for sorting out:
Check according to the process in effect for data permissions:

  • Look at the log and see if there are any errors. When the data rights interceptor fails, it will also query all the data.
  • Modify the interface to check for changes in redis, database data:
  • Check hpfm:permission:{table name} for redis db1, which is the direct source of filtering rules;
  • Check database hzero_platform.HPFM_PERMISSION_RANGE, redis data comes from here;

Other

hzero's data rights seem flexible and powerful, but they are cumbersome to maintain, difficult to use, and prone to problems.

Prerequisites for using data permissions: access to hzero_ Tables under the platform, so you need to: use the same database instance with the platform and have access rights;

All services on the platform need to share a redis, a database instance, and the platform is equivalent to a distributed monolithic application.

Role inheritance cannot inherit data permissions;

hiam_role_auth_data_line.data_id is numeric and cannot store string; So there is no way to filter strings by mapping/associating numbers first;

Recommended ideas for controlling data permissions: control the filter conditions of queries according to the permission set of roles;

Keywords: Microservices

Added by telefiend on Wed, 01 Dec 2021 21:57:14 +0200