没有不值得去解决的问题,也没有不值得去学习的技术!

Refactoring CMC Framework Menus and Permissions: Separating Permissions From Menus and Categorizing Permissions to Avoid Excessive Menu Additions During Upgrades

After adding the menu at the service level, edit/check the menu in the service under the tenant level.

1. In the current implementation, menus and permissions have a one-to-one correspondence. The management interface in the framework is shown in Figure 1.

In the current implementation, menus and permissions have a one-to-one correspondence. The management interface in the framework.
Figure 1

2. The design structure is as follows:

Plaintext
	Topic management: /plans(plan/index-category) 
		My topics: /plans/have(plan/have) 
			New (create topic): /plans(plan/create)
			Get topic column settings list (required when creating a topic): /plan-config-columns(plan-config-column/index)
			Edit topic: /plans/edit/{id}(plan/edit)
			Edit (update topic): /plans/{id}(plan/update)   
			Delete (delete topic): /plans/{id}(plan/delete)
			Enable (enable topic): /plans/enable/{ids}(plan/enable)
			Disable (disable topic): /plans/disable/{ids}(plan/disable)   
			Submit (submit topic): /plans/submit/{id}(plan/submit)
			Move up/down (sort topics): /plans/sort/{id}(plan/sort) 
			Return (return topic): /plans/return/{id}(plan/return)
			Get public opinion (public opinion big data) details: /yqdsj-article/{id}(yqdsj-article/view)
			Invite (joint topic): /plans/invite/{id}(plan/invite)
			Get the CMC tenant list for the topic: /plans/cmc-group/{id}(plan/cmc-group) 
			Get the invited tenant list for the (joint) topic: /plan-group-relations(plan-group-relation/index)
			Accept invitation (joint topic): /plans/invite-accept/{id}(plan/invite-accept)
			Reject invitation (joint topic): /plans/invite-refuse/{id}(plan/invite-refuse)
			Get details of the IM group for the topic: /im-groups/{id}(im-group/view)
			Get the user list of the IM group: /im-group-users(im-group-user/index)
			Upload topic resource: /plan-assets/upload(plan-asset/upload)
			Create topic resource: /plan-assets(plan-asset/create)
            Delete topic resource: /plan-assets/{id}(plan-asset/delete)
			Get topic column personnel configuration list (required when creating, editing, and updating a topic): /plan-config-column-users(plan-config-column-user/index)
		Topics pending review: /plans/wait-review(plan/wait-review) 
			Reject (reject topic): /plans/refuse/{id}(plan/refuse)
			Pass (pass topic): /plans/pass/{id}(plan/pass)
		Topic query: /plans(plan/index)
			Details (get topic details): /plans/{id}(plan/view)
			Get topic log list: /plan-logs(plan-log/index)
			Get topic material list: /plan-resources(plan-resource/index)
	Task management: /plan-tasks(plan-task/index-category)
		My tasks: /plan-tasks(plan-task/index)
			Details (get task details): /plan-tasks/{id}(plan-task/view)
			Assign (create task): /plan-tasks(plan-task/create)
			Edit (get edit task data): /plan-tasks/edit/{id}(plan-task/edit)
			Edit (update task): /plan-tasks/{id}(plan-task/update)
			Delete (delete task): /plan-tasks/{ids}(plan-task/delete)
			Claim (claim task): /plan-tasks/claim/{ids}(plan-task/claim)
			Transfer (transfer task): /plan-tasks/transfer/{id}(plan-task/transfer)   
			Complete (complete task): /plan-tasks/finish/{ids}(plan-task/finish)
			Disable (disable task): /plan-tasks/disable/{ids}(plan-task/disable)
			Enable (enable task): /plan-tasks/enable/{ids}(plan-task/enable)
			Get write article (SCMS) link: /plan-tasks/write/{id}(plan-task/write)
			Get submit article (SCMS) link: /plan-tasks/commit-article/{id}(plan-task/commit-article)
			Get article review (SCMS) link: /plan-tasks/article-review/{id}(plan-task/article-review)
			Get video editing (Jove micro-editing, Nova fine-editing) link: /plan-tasks/video-edit/{id}(plan-task/video-edit)
			Get upload material (CPU) link: /plan-tasks/upload/{id}(plan-task/upload)  
			Related materials: /plan-task-resources(plan-task-resource/index)
			Delete materials: /plan-task-resources/{ids}(plan-task-resource/delete)
			Get configured task steps (required when creating a task): /config-task-steps(config-task-step/index)
			Create task log: /plan-tasks/log/{id}(plan-task/log-create)
			Get task log list: /plan-task-logs(plan-task-log/index)
			Get task column personnel configuration list (required when creating a task, creating participating users for a task, and editing participating users for a task): /plan-task-config-column-users(plan-task-config-column-user/index)
			Get participating users of the topic task: /plan-task-attended-users(plan-task-attended-user/index)
			Update, delete, and add participating users of the topic task: /plan-task-attended-users/{plan_task_id}(plan-task-attended-user/update)
			Delete participating users of the topic task: /plan-task-attended-users/{ids}(plan-task-attended-user/delete)
	Basic settings: /config-columns(config-column/index-category)
		Column settings: /config-columns(config-column/index-link)
			Column management (get column settings list): /config-columns(config-column/index)
			New (create column settings): /config-columns(config-column/create)
			Modify (update column settings): /config-columns/{id}(config-column/update)
			Delete (delete column settings): /config-columns/{id}(config-column/delete)
			Whether to enable (enable/disable column settings): /config-columns/enable-disable/{id}(config-column/enable-disable) 
			Column personnel management (get column personnel settings list): /config-column-users(config-column-user/index)
			Personnel change (update column personnel settings): /config-column-users/{config_column_id}(config-column-user/update)
			Delete (delete column personnel configuration): /config-column-users/{ids}(config-column-user/delete)
			Identity change (update the role identifier of column personnel settings): /config-column-users/role-code/{id}(config-column-user/role-code)
			Get CMC user list: /cmc-users(cmc-user/index)
			Get role (member identity) list: /roles(role/index)
		Base settings: /config-base-locations/edit/my-group-id(config-base-location/edit)
			Update base settings: /config-base-locations/my-group-id(config-base-location/update)
		System logs: /logs(log/index-link)
			Get log list: /logs(log/index)
			Get log details: /logs/{id}(log/view)
		Task settings (get task settings list): /config-plan-tasks(config-plan-task/index) 
	GIS screen: /gis/index.html(gis/index-category)
		GIS screen: https://pcs.wjdev.chinamcloud.cn/gis/index.html(gis/index-link)
			Get GIS screen task list: /gis-tasks/list(gis-task/list)
			Get GIS screen reporter list: /gis-user-places/list(gis-user-place/list)
			Get GIS screen topic list: /gis-plans/index(gis-plan/index)  
			Get GIS screen tenant list: /gis-groups/index(gis-group/index)
			Get GIS screen topic quantity trend list: /gis-plan-quantity-trends/index(gis-plan-quantity-trend/index)
		GIS screen interface: /gis-tasks/list(gis-task/list-link)
			RTC invite call close: /gis-rtcs/room-close(gis-rtc/room-close)
			RTC invite call: /gis-rtcs/invite(gis-rtc/invite)
			RTC configuration: /gis-rtcs/config(gis-rtc/config)
			Base data: /gis-locations(gis-location/one)
			RTC call kick user: /gis-rtcs/room-remove-user(gis-rtc/room-remove-user)
		Statistics ranking: /gis-top-plans(gis-top-plan/index-link)
			Task overview: /gis-top-plan-tasks(gis-top-plan-task/index)
			Material list: /gis-resources/list(gis-resource/list)
			Reporter performance: /gis-top-reporters(gis-top-reporter/index)
			Topic planning: /gis-top-plans(gis-top-plan/index) 
	Cross-tenant topic management: /cross-group-plans(cross-group-plan/index-category) 
		Cross-tenant my topics (get topic list): /cross-group-plans/have(cross-group-plan/have)
			Cross-tenant enable (enable topic): /cross-group-plans/enable/{ids}(cross-group-plan/enable)
			Cross-tenant disable (disable topic): /cross-group-plans/disable/{ids}(cross-group-plan/disable)   
			Cross-tenant details (get topic details): /cross-group-plans/{id}(cross-group-plan/view) 
	Mobile: /mobiles(mobile/index-category) 
		Topics: /mobile/plans(mobile/plan/index-link)   
			Get topic column personnel configuration list (required when creating, editing, and updating a topic): /mobile/plan-config-column-users(mobile/plan-config-column-user/index)
			Get topic column settings list: /mobile/plan-config-columns(mobile/plan-config-column/index)
			New (create topic): /mobile/plans(mobile/plan/create)
			Edit topic: /mobile/plans/edit/{id}(mobile/plan/edit)
			Update topic: /mobile/plans/{id}(mobile/plan/update)
			My topics (get topic list): /mobile/plans/have(mobile/plan/have)
			Details (get topic details): /mobile/plans/{id}(mobile/plan/view)
			Topics pending review (get topic list): /mobile/plans/wait-review(mobile/plan/wait-review)
			Topic query (get topic list): /mobile/plans(mobile/plan/index)
			Reject (reject topic): /mobile/plans/refuse/{id}(mobile/plan/refuse)
			Pass (pass topic): /mobile/plans/pass/{id}(mobile/plan/pass)
			Get topic log list: /mobile/plan-logs(mobile/plan-log/index)
			Get topic material list: /mobile/plan-resources(mobile/plan-resource/index)
		Tasks: /mobile/plan-tasks(mobile/plan-task/index-link) 
			My tasks (get task list): /mobile/plan-tasks(mobile/plan-task/index)
			Get task column personnel configuration list (required when creating a task, creating participating users for a task, and editing participating users for a task): /mobile/plan-task-config-column-users/{plan_id}(mobile/plan-task-config-column-user/index)
			Get configured task steps (required when creating a task): /mobile/config-task-steps(mobile/config-task-step/index)
			Assign (create task): /mobile/plan-tasks(mobile/plan-task/create)
			Details (get task details): /mobile/plan-tasks/{id}(mobile/plan-task/view)
			Claim (claim task): /mobile/plan-tasks/claim/{ids}(mobile/plan-task/claim)
			Transfer (transfer task): /mobile/plan-tasks/transfer/{id}(mobile/plan-task/transfer)
			Related materials: /mobile/plan-task-resources(mobile/plan-task-resource/index)
			Delete materials: /mobile/plan-task-resources/{id}(mobile/plan-task-resource/delete)
			Create task log: /mobile/plan-tasks/log/{id}(mobile/plan-task/log-create)
			Get task log list: /mobile/plan-task-logs(mobile/plan-task-log/index)
			Get participating users of the topic task: /mobile/plan-task-attended-users(mobile/plan-task-attended-user/index)
			Update, delete, and add participating users of the topic task: /mobile/plan-task-attended-users/{plan_task_id}(mobile/plan-task-attended-user/update)
			Edit (get edit task data): /mobile/plan-tasks/edit/{id}(mobile/plan-task/edit)
			Update task: /mobile/plan-tasks/{id}(mobile/plan-task/update)
			Complete (complete task): /mobile/plan-tasks/finish/{ids}(mobile/plan-task/finish)
			IM all user list: /mobile/ims/users(mobile/im/users)
			RTC user room: /mobile/rtcs/rooms(mobile/rtc/rooms)
			RTC configuration: /mobile/rtcs/config(mobile/rtc/config)
			Task step completion: /mobile/plan-task-steps/end/{task_step_id}(mobile/plan-task-step/end)
			Statistics by task status: /mobile/plan-tasks/status-count(mobile/plan-task/status-count)
			Aurora delete alias: /mobile/jgs/{id}(mobile/jg/delete)
			Material upload: /mobile/resources/resource(mobile/resource/create)
			Reporter location upload: /mobile/user-places(mobile/user-place/create)
		Mine: /mobile/mys(mobile/my/index-link)
		    Task overview: /mobile/my-top-plan-tasks(mobile/my-top-plan-task/index)
			Reporter performance: /mobile/my-top-reporters(mobile/my-top-reporter/index)

3. If you need to add a new menu/permission (example: Mobile – Tasks – Complete (complete task): /mobile/plan-tasks/finish/{ids}(mobile/plan-task/finish)), the operation steps are roughly as follows. First, add the menu at the service level, as shown in Figure 2.

If you need to add a new menu/permission (example: Mobile - Tasks - Complete (complete task): /mobile/plan-tasks/finish/{ids}(mobile/plan-task/finish)), the operation steps are roughly as follows. First, add the menu at the service level.
Figure 2

4. Second, edit/check the menu in the service under the tenant level, as shown in Figure 3.

Second, edit/check the menu in the service under the tenant level.
Figure 3

5. Third, edit/check the menu in the role under the user level, as shown in Figure 4.

Third, edit/check the menu in the role under the user level.
Figure 4

6. The problem encountered at this stage is that if PCS is used by 10 tenants, and among the roles under these 10 tenants, 3 roles all need to check the newly added menu, then if a new menu/permission needs to be added, the number of operations required is: 1 + 10 + (10 * 3) = 41. In fact, in a cloud environment, the number of tenants is far more than 10, and even if menu/permission management is implemented programmatically, only the first and second steps can be implemented; the third step cannot be implemented (number of operations: 1 + 10 + (10 * 3) – 1 – 10 = 30.). This is because the roles under each tenant are inconsistent and can be completely customized by the user.

7. In response to the problems encountered at this stage, the solution is roughly planned as follows: refactoring of menus and permissions (separation of permissions and menus, permission classification), that is, separating permissions from menus so they no longer correspond one-to-one. This way, the need for menu display can reduce the number of menu configurations, because for menu display, generally only the first and second levels are sufficient. As shown in Figure 5.

In response to the problems encountered at this stage, the solution is roughly planned as follows: refactoring of menus and permissions (separation of permissions and menus, permission classification), that is, separating permissions from menus so they no longer correspond one-to-one. This way, the need for menu display can reduce the number of menu configurations, because for menu display, generally only the first and second levels are sufficient.
Figure 5

8. Permission classification divides all permissions into different categories. It is temporarily decided that the classification will also be divided into only four levels. Permissions under a certain category are configured in the program. This way, if you need to add a new menu/permission (example: Mobile – Tasks – Complete (complete task): /mobile/plan-tasks/finish/{ids}(mobile/plan-task/finish)), you only need to add a new configuration item in the program. This is because the category it belongs to already exists in the framework. Only when the category of a newly added menu/permission does not exist in the framework do you need to execute the first, second, and third steps based on the previous steps.

9. The final structure of the menu is as follows (to prevent permission identifier conflicts, category-type menus have added the suffix: -menu-category, and link-type menus have added the suffix: -menu-link):

Plaintext
Menu structure:
Topic management: /plans(plan/index-menu-category)
    My topics: /plans/have(plan/have-menu-link)
    Topics pending review: /plans/wait-review(plan/wait-review-menu-link)
    Topic query: /plans(plan/index-menu-link)
Task management: /plan-tasks(plan-task/index-menu-category)
    My tasks: /plan-tasks(plan-task/index-menu-link)
Basic settings: /config-columns(config-column/index-menu-category)
    Column settings: /config-columns(config-column/index-menu-link)
    Base settings: /config-base-locations/edit/my-group-id(config-base-location/edit-menu-link)
    System logs: /logs(log/index-menu-link)
GIS screen: /gis/index.html(gis/index-menu-category)
    GIS screen: https://pcs.wjdev.chinamcloud.cn/gis/index.html(gis/index-menu-link)

10. The final structure of permissions is as follows (to prevent permission identifier conflicts, category-type permissions have added the suffix: -permission-category, link-type permissions have added the suffix: -permission-link, and button-type permissions have added the suffix: -permission-button):

Plaintext
Permission structure:
[Permission] Topic management: /plans(plan/index-permission-category)
    [Permission] My topics: /plans/have(plan/have-permission-link)
        [Permission] New topic: /plans(plan/create-permission-button)
            My topics (get topic list): /plans/have(plan/have)
            Get topic column settings list (required when creating a topic): /plan-config-columns(plan-config-column/index)
            Get topic column personnel configuration list (required when creating, editing, and updating a topic): /plan-config-column-users(plan-config-column-user/index)
            New (create topic): /plans(plan/create)
            Details (get topic details): /plans/{id}(plan/view)
        [Permission] My topics (get topic list): /plans/have(plan/have-permission-button)
            My topics (get topic list): /plans/have(plan/have)
            Get topic column personnel configuration list (required when creating, editing, and updating a topic): /plan-config-column-users(plan-config-column-user/index)
            Edit topic: /plans/edit/{id}(plan/edit)
            Update topic: /plans/{id}(plan/update)   
            Delete topic: /plans/{id}(plan/delete)
            Enable topic: /plans/enable/{ids}(plan/enable)
            Disable topic: /plans/disable/{ids}(plan/disable)   
            Submit topic: /plans/submit/{id}(plan/submit)
            Reject topic: /plans/refuse/{id}(plan/refuse)
            Pass topic: /plans/pass/{id}(plan/pass)
            Return topic: /plans/return/{id}(plan/return)
            Get public opinion (public opinion big data) details: /yqdsj-articles/{id}(yqdsj-article/view)
            Get public opinion (third-party public opinion big data) details: /sfyqdsj-articles(sfyqdsj-article/fill)
            Invite (joint topic): /plans/invite/{id}(plan/invite)
            Get the CMC tenant list for the topic: /plans/cmc-group/{id}(plan/cmc-group) 
            Get the invited tenant list for the (joint) topic: /plan-group-relations(plan-group-relation/index)
            Accept invitation (joint topic): /plans/invite-accept/{id}(plan/invite-accept)
            Get details of the IM group for the topic: /im-groups/{id}(im-group/view)
            Get the user list of the IM group: /im-group-users(im-group-user/index)
            Upload topic resource: /plan-assets/upload(plan-asset/upload)
            Details (get topic details): /plans/{id}(plan/view)
            Get topic log list: /plan-logs(plan-log/index)
            Get topic material list: /plan-resources(plan-resource/index)
            My tasks (get task list): /plan-tasks(plan-task/index)
            Get configured task steps (required when creating a task): /config-task-steps(config-task-step/index)
            Get task column personnel configuration list (required when creating a task, creating participating users for a task, and editing participating users for a task): /plan-task-config-column-users(plan-task-config-column-user/index)
            Assign (create task): /plan-tasks(plan-task/create)
    [Permission] Topics pending review: /plans/wait-review(plan/wait-review-permission-link)
        Topics pending review (get topic list): /plans/wait-review(plan/wait-review)
        Reject topic: /plans/refuse/{id}(plan/refuse)
        Pass topic: /plans/pass/{id}(plan/pass)
        Details (get topic details): /plans/{id}(plan/view)
    [Permission] Topic query: /plans(plan/index-permission-link)
        Topic query (get topic list): /plans(plan/index)
        Details (get topic details): /plans/{id}(plan/view)
        Get topic log list: /plan-logs(plan-log/index)
        Get topic material list: /plan-resources(plan-resource/index)
        My tasks (get task list): /plan-tasks(plan-task/index)
[Permission] Task management: /plan-tasks(plan-task/index-permission-category)
    [Permission] My tasks: /plan-tasks(plan-task/index-permission-link)
        My tasks (get task list): /plan-tasks(plan-task/index)
        Details (get task details): /plan-tasks/{id}(plan-task/view)
        Get configured task steps (required when creating a task): /config-task-steps(config-task-step/index)
        Get task column personnel configuration list (required when creating a task, creating participating users for a task, and editing participating users for a task): /plan-task-config-column-users(plan-task-config-column-user/index)
        Assign (create task): /plan-tasks(plan-task/create)
        Edit task: /plan-tasks/edit/{id}(plan-task/edit)
        Update task: /plan-tasks/{id}(plan-task/update)
        Delete task: /plan-tasks/{ids}(plan-task/delete)
        Claim task: /plan-tasks/claim/{ids}(plan-task/claim)
        Transfer task: /plan-tasks/transfer/{id}(plan-task/transfer)   
        Complete task: /plan-tasks/finish/{ids}(plan-task/finish)
        Disable task: /plan-tasks/disable/{ids}(plan-task/disable)
        Enable task: /plan-tasks/enable/{ids}(plan-task/enable)
        Get write article (SCMS) link: /plan-tasks/write/{id}(plan-task/write)
        Get submit article (SCMS) link: /plan-tasks/commit-article/{id}(plan-task/commit-article)
        Get article review (SCMS) link: /plan-tasks/article-review/{id}(plan-task/article-review)
        Get video editing (Jove micro-editing, Nova fine-editing) link: /plan-tasks/video-edit/{id}(plan-task/video-edit)
        Get upload material (CPU) link: /plan-tasks/upload/{id}(plan-task/upload)  
        Related materials: /plan-task-resources(plan-task-resource/index)
        Delete materials: /plan-task-resources/{ids}(plan-task-resource/delete)
        Create task log: /plan-tasks/log/{id}(plan-task/log-create)
        Get task log list: /plan-task-logs(plan-task-log/index)
        Get participating users of the topic task: /plan-task-attended-users(plan-task-attended-user/index)
        Update, delete, and add participating users of the topic task: /plan-task-attended-users/{plan_task_id}(plan-task-attended-user/update)
        Delete participating users of the topic task: /plan-task-attended-users/{ids}(plan-task-attended-user/delete)
[Permission] Basic settings: /config-columns(config-column/index-permission-category)
    [Permission] Column management: /config-columns(config-column/index-permission-link)
        Get column settings list: /config-columns(config-column/index)
        New (create column settings): /config-columns(config-column/create)
        Modify (update column settings): /config-columns/{id}(config-column/update)
        Delete (delete column settings): /config-columns/{id}(config-column/delete)
        Column personnel management (get column personnel settings list): /config-column-users(config-column-user/index)
        Personnel change (update column personnel settings): /config-column-users/{config_column_id}(config-column-user/update)
        Delete (delete column personnel configuration): /config-column-users/{ids}(config-column-user/delete)
        Identity change (update the role identifier of column personnel settings): /config-column-users/role-code/{id}(config-column-user/role-code)
        Get CMC user list: /cmc-users(cmc-user/index)
        Get role (member identity) list: /roles(role/index)
    [Permission] Base settings: /config-base-locations/edit/my-group-id(config-base-location/edit-permission-link)
        Edit base settings: /config-base-locations/edit/my-group-id(config-base-location/edit)
        Update base settings: /config-base-locations/my-group-id(config-base-location/update)
    [Permission] System logs: /logs(log/index-permission-link)
        Get log list: /logs(log/index)
        Get log details: /logs/{id}(log/view)
[Permission] GIS screen: /gis/index.html(gis/index-permission-category)
    [Permission] GIS screen: /gis-tasks/list(gis-task/list-permission-link)
        Get GIS screen task list: /gis-tasks/list(gis-task/list)
        Get GIS screen reporter list: /gis-user-places/list(gis-user-place/list)
        RTC invite call close: /gis-rtcs/room-close(gis-rtc/room-close)
        RTC invite call: /gis-rtcs/invite(gis-rtc/invite)
        RTC configuration: /gis-rtcs/config(gis-rtc/config)
        Base data: /gis-locations(gis-location/one)
        RTC call kick user: /gis-rtcs/room-remove-user(gis-rtc/room-remove-user)
    [Permission] Statistics ranking: /gis-top-plans(gis-top-plan/index-permission-link)
        Task overview: /gis-top-plan-tasks(gis-top-plan-task/index)
        Material list: /gis-resources/list(gis-resource/list)
        Reporter performance: /gis-top-reporters(gis-top-reporter/index)
        Topic planning: /gis-top-plans(gis-top-plan/index) 
[Permission] Cross-tenant topic management: /cross-group-plans/have(cross-group-plan/have-permission-category) 
    [Permission] Cross-tenant my topics: /cross-group-plans/have(cross-group-plan/have-permission-link)
        Cross-tenant my topics (get topic list): /cross-group-plans/have(cross-group-plan/have)
        Cross-tenant get the CMC tenant list for the topic: /cross-group-plans/cmc-group/{id}(cross-group-plan/cmc-group)
        Cross-tenant enable (enable topic): /cross-group-plans/enable/{ids}(cross-group-plan/enable)
        Cross-tenant disable (disable topic): /cross-group-plans/disable/{ids}(cross-group-plan/disable)   
        Cross-tenant details (get topic details): /cross-group-plans/{id}(cross-group-plan/view)
[Permission] Mobile: /mobiles(mobile/index-permission-category)
    [Permission] Topic management: /mobile/plans(mobile/plan/index-permission-category)
        [Permission] My topics: /mobile/plans/have(mobile/plan/have-permission-link)
            [Permission] New topic: /mobile/plans(mobile/plan/create-permission-button)
                My topics (get topic list): /mobile/plans/have(mobile/plan/have)
                Get topic column settings list (required when creating a topic): /mobile/plan-config-columns(mobile/plan-config-column/index)
                Get topic column personnel configuration list (required when creating, editing, and updating a topic): /mobile/plan-config-column-users(mobile/plan-config-column-user/index)
                New (create topic): /mobile/plans(mobile/plan/create)
                Details (get topic details): /mobile/plans/{id}(mobile/plan/view)
            [Permission] My topics (get topic list): /mobile/plans/have(mobile/plan/have-permission-button)
                My topics (get topic list): /mobile/plans/have(mobile/plan/have)
                Get topic column personnel configuration list (required when creating, editing, and updating a topic): /mobile/plan-config-column-users(mobile/plan-config-column-user/index)
                Edit topic: /mobile/plans/edit/{id}(mobile/plan/edit)
                Update topic: /mobile/plans/{id}(mobile/plan/update)
                Reject topic: /mobile/plans/refuse/{id}(mobile/plan/refuse)
                Pass topic: /mobile/plans/pass/{id}(mobile/plan/pass)
                Details (get topic details): /mobile/plans/{id}(mobile/plan/view)
                Get topic log list: /mobile/plan-logs(mobile/plan-log/index)
                Get topic material list: /mobile/plan-resources(mobile/plan-resource/index)
                My tasks (get task list): /mobile/plan-tasks(mobile/plan-task/index)
                Get configured task steps (required when creating a task): /mobile/config-task-steps(mobile/config-task-step/index)
                Get task column personnel configuration list (required when creating a task, creating participating users for a task, and editing participating users for a task): /mobile/plan-task-config-column-users/{plan_id}(mobile/plan-task-config-column-user/index)
                Assign (create task): /mobile/plan-tasks(mobile/plan-task/create)
        [Permission] Topics pending review: /mobile/plans/wait-review(mobile/plan/wait-review-permission-link)
            Topics pending review (get topic list): /mobile/plans/wait-review(mobile/plan/wait-review)
            Reject topic: /mobile/plans/refuse/{id}(mobile/plan/refuse)
            Pass topic: /mobile/plans/pass/{id}(mobile/plan/pass)
            Details (get topic details): /mobile/plans/{id}(mobile/plan/view)
        [Permission] Topic query: /mobile/plans(mobile/plan/index-permission-link)
            Topic query (get topic list): /mobile/plans(mobile/plan/index)
            Details (get topic details): /mobile/plans/{id}(mobile/plan/view)
            Get topic log list: /mobile/plan-logs(mobile/plan-log/index)
            Get topic material list: /mobile/plan-resources(mobile/plan-resource/index)
            My tasks (get task list): /mobile/plan-tasks(mobile/plan-task/index)
    [Permission] Task management: /mobile/plan-tasks(mobile/plan-task/index-permission-category)
        [Permission] My tasks: /mobile/plan-tasks(mobile/plan-task/index-permission-link)
            My tasks (get task list): /mobile/plan-tasks(mobile/plan-task/index)
            Details (get task details): /mobile/plan-tasks/{id}(mobile/plan-task/view)
            Get configured task steps (required when creating a task): /mobile/config-task-steps(mobile/config-task-step/index)
            Get task column personnel configuration list (required when creating a task, creating participating users for a task, and editing participating users for a task): /mobile/plan-task-config-column-users/{plan_id}(mobile/plan-task-config-column-user/index)
            Assign (create task): /mobile/plan-tasks(mobile/plan-task/create)
            Edit task: /mobile/plan-tasks/edit/{id}(mobile/plan-task/edit)
            Update task: /mobile/plan-tasks/{id}(mobile/plan-task/update)
            Claim task: /mobile/plan-tasks/claim/{ids}(mobile/plan-task/claim)
            Transfer task: /mobile/plan-tasks/transfer/{id}(mobile/plan-task/transfer)
            Complete task: /mobile/plan-tasks/finish/{ids}(mobile/plan-task/finish)
            Related materials: /mobile/plan-task-resources(mobile/plan-task-resource/index)
            Delete materials: /mobile/plan-task-resources/{id}(mobile/plan-task-resource/delete)
            Create task log: /mobile/plan-tasks/log/{id}(mobile/plan-task/log-create)
            Get task log list: /mobile/plan-task-logs(mobile/plan-task-log/index)
            Get participating users of the topic task: /mobile/plan-task-attended-users(mobile/plan-task-attended-user/index)
            Update, delete, and add participating users of the topic task: /mobile/plan-task-attended-users/{plan_task_id}(mobile/plan-task-attended-user/update)
            IM all user list: /mobile/ims/users(mobile/im/users)
            RTC user room: /mobile/rtcs/rooms(mobile/rtc/rooms)
            RTC configuration: /mobile/rtcs/config(mobile/rtc/config)
            Complete task step: /mobile/plan-task-steps/end/{task_step_id}(mobile/plan-task-step/end)
            Statistics task (by status): /mobile/plan-tasks/status-count(mobile/plan-task/status-count)
            Delete Aurora push alias: /mobile/jgs/{id}(mobile/jg/delete)
            Upload material: /mobile/resources/resource(mobile/resource/create)
            Reporter location upload: /mobile/user-places(mobile/user-place/create)
    [Permission] Mine: /mobile/mys(mobile/my/index-permission-category)
        [Permission] Mine: /mobile/mys(mobile/my/index-permission-link)
            Task overview: /mobile/my-top-plan-tasks(mobile/my-top-plan-task/index)
            Reporter performance: /mobile/my-top-reporters(mobile/my-top-reporter/index)

11. After adding the menu at the service level, edit/check the menu in the service under the tenant level, as shown in Figure 6.

After adding the menu at the service level, edit/check the menu in the service under the tenant level.
Figure 6

12. Edit the file: \common\config\params.php to add the framework service permission configuration.

PHP

    // 框架服务权限
    'cmcPermission' => [
        'plan/index-permission-category' => [
            'plan/have-permission-link' => [
                'plan/create-permission-button' => [
                    'plan/have',
                    'plan-config-column/index',
                    'plan-config-column-user/index',
                    'plan/create',
                    'plan/view',
                ],
                'plan/have-permission-button' => [
                    'plan/have',
                    'plan-config-column-user/index',
                    'plan/edit',
                    'plan/update',
                    'plan/delete',
                    'plan/enable',
                    'plan/disable',
                    'plan/submit',
                    'plan/refuse',
                    'plan/pass',
                    'plan/return',
                    'yqdsj-article/view',
                    'sfyqdsj-article/fill',
                    'plan/invite',
                    'plan/cmc-group',
                    'plan-group-relation/index',
                    'plan/invite-accept',
                    'im-group/view',
                    'im-group-user/index',
                    'plan-asset/upload',
                    'plan/view',
                    'plan-log/index',
                    'plan-resource/index',
                    'plan-task/index',
                    'config-task-step/index',
                    'plan-task-config-column-user/index',
                    'plan-task/create',
                ],
            ],
            'plan/wait-review-permission-link' => [
                'plan/wait-review',
                'plan/refuse',
                'plan/pass',
                'plan/view',
            ],
            'plan/index-permission-link' => [
                'plan/index',
                'plan/view',
                'plan-log/index',
                'plan-resource/index',
                'plan-task/index',
            ],
        ],
        'plan-task/index-permission-category' => [
            'plan-task/index-permission-link' => [
                'plan-task/index',
                'plan-task/view',
                'config-task-step/index',
                'plan-task-config-column-user/index',
                'plan-task/create',
                'plan-task/edit',
                'plan-task/update',
                'plan-task/delete',
                'plan-task/claim',
                'plan-task/transfer',
                'plan-task/finish',
                'plan-task/disable',
                'plan-task/enable',
                'plan-task/write',
                'plan-task/commit-article',
                'plan-task/article-review',
                'plan-task/video-edit',
                'plan-task/upload',
                'plan-task-resource/index',
                'plan-task-resource/delete',
                'plan-task/log-create',
                'plan-task-log/index',
                'plan-task-attended-user/index',
                'plan-task-attended-user/update',
                'plan-task-attended-user/delete',
            ],
        ],
        'config-column/index-permission-category' => [
            'config-column/index-permission-link' => [
                'config-column/index',
                'config-column/create',
                'config-column/update',
                'config-column/delete',
                'config-column-user/index',
                'config-column-user/update',
                'config-column-user/delete',
                'config-column-user/role-code',
                'cmc-user/index',
                'role/index',
            ],
            'config-base-location/edit-permission-link' => [
                'config-base-location/edit',
                'config-base-location/update',
            ],
            'log/index-permission-link' => [
                'log/index',
                'log/view',
            ],
        ],
        'gis/index-permission-category' => [
            'gis-task/list-permission-link' => [
                'gis-task/list',
                'gis-user-place/list',
                'gis-rtc/room-close',
                'gis-rtc/invite',
                'gis-rtc/config',
                'gis-location/one',
                'gis-rtc/room-remove-user',
            ],
            'gis-top-plan/index-permission-link' => [
                'gis-top-plan-task/index',
                'gis-resource/list',
                'gis-top-reporter/index',
                'gis-top-plan/index',
            ],
        ],
        'cross-group-plan/have-permission-category' => [
            'cross-group-plan/have-permission-link' => [
                'cross-group-plan/have',
                'cross-group-plan/cmc-group',
                'cross-group-plan/enable',
                'cross-group-plan/disable',
                'cross-group-plan/view',
            ],
        ],
        'mobile/index-permission-category' => [
            'mobile/plan/index-permission-category' => [
                'mobile/plan/have-permission-link' => [
                    'mobile/plan/create-permission-button' => [
                        'mobile/plan/have',
                        'mobile/plan-config-column/index',
                        'mobile/plan-config-column-user/index',
                        'mobile/plan/create',
                        'mobile/plan/view',
                    ],
                    'mobile/plan/have-permission-button' => [
                        'mobile/plan/have',
                        'mobile/plan-config-column-user/index',
                        'mobile/plan/edit',
                        'mobile/plan/update',
                        'mobile/plan/refuse',
                        'mobile/plan/pass',
                        'mobile/plan/view',
                        'mobile/plan-log/index',
                        'mobile/plan-resource/index',
                        'mobile/plan-task/index',
                        'mobile/config-task-step/index',
                        'mobile/plan-task-config-column-user/index',
                        'mobile/plan-task/create',
                    ],
                ],
                'mobile/plan/wait-review-permission-link' => [
                    'mobile/plan/wait-review',
                    'mobile/plan/refuse',
                    'mobile/plan/pass',
                    'mobile/plan/view',
                ],
                'mobile/plan/index-permission-link' => [
                    'mobile/plan/index',
                    'mobile/plan/view',
                    'mobile/plan-log/index',
                    'mobile/plan-resource/index',
                    'mobile/plan-task/index',
                ],
            ],
            'mobile/plan-task/index-permission-category' => [
                'mobile/plan-task/index-permission-link' => [
                    'mobile/plan-task/index',
                    'mobile/plan-task/view',
                    'mobile/config-task-step/index',
                    'mobile/plan-task-config-column-user/index',
                    'mobile/plan-task/create',
                    'mobile/plan-task/edit',
                    'mobile/plan-task/update',
                    'mobile/plan-task/claim',
                    'mobile/plan-task/transfer',
                    'mobile/plan-task/finish',
                    'mobile/plan-task-resource/index',
                    'mobile/plan-task-resource/delete',
                    'mobile/plan-task/log-create',
                    'mobile/plan-task-log/index',
                    'mobile/plan-task-attended-user/index',
                    'mobile/plan-task-attended-user/update',
                    'mobile/im/users',
                    'mobile/rtc/rooms',
                    'mobile/rtc/config',
                    'mobile/plan-task-step/end',
                    'mobile/plan-task/status-count',
                    'mobile/jg/delete',
                    'mobile/resource/create',
                    'mobile/user-place/create',
                ],
            ],
            'mobile/my/index-permission-category' => [
                'mobile/my/index-permission-link' => [
                    'mobile/my-top-plan-task/index',
                    'mobile/my-top-reporter/index',
                ],
            ],
        ],
    ],

13. When calling an interface, confirming its category permission identifier involves getting the array key of its parent dimension. There may be multiple array keys. The same interface may belong to more than one permission category. For example: Get topic column personnel configuration list (required when creating, editing, and updating a topic) exists in both the New topic and Update topic categories. When this happens, the CMC framework interface is called sequentially based on the permission category identifiers until one with a matching permission category identifier is found. Or, if it reaches the end without finding a permission category identifier, it responds that there is no permission for the corresponding interface. Note: Subsequent CMC frameworks need to support permission identifiers in array format to avoid multiple calls to the CMC framework interface. When calling the interface: Get topic column personnel configuration list (required when creating, editing, and updating a topic), its category permission identifier value is: [‘plan/create-permission-button’, ‘plan/have-permission-button’]. As shown in Figure 7.

When calling an interface, confirming its category permission identifier involves getting the array key of its parent dimension. There may be multiple array keys.
Figure 7

14. Call the interface in Postman: http://api.pcs-api.localhost/v1/plan-config-column-users?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=0b0f8b3f90a7afc91bf5416c283053df&filter[config_column_id]=1 , the response is as follows.

JSON

{
    "name": "Forbidden",
    "message": "用户授权失败:plan-config-column-user/index,不允许访问",
    "code": 201012,
    "status": 403,
    "type": "yii\\web\\ForbiddenHttpException"
}

15. Check the logs to get user permissions through the framework service permission identifier. The permission identifier is the identifier of the interface itself, as shown in Figure 8.

Check the logs to get user permissions through the framework service permission identifier. The permission identifier is the identifier of the interface itself.
Figure 8

16. Edit \common\behaviors\GlobalAccessBehavior.php and add a new method to get the array key name of its parent based on the interface identifier, formatted as an array.

PHP
<?php
 
namespace common\behaviors;
 
/**
 * Class GlobalAccessBehavior
 * @package common\behaviors
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */
class GlobalAccessBehavior extends Behavior
{

    /**
     * @inheritdoc
     *
     * @throws HttpException 未登录
     * @throws InvalidConfigException 如果注册的解析器没有实现 [[RequestParserInterface]]
     * @throws ServerErrorHttpException
     * @throws ForbiddenHttpException 当前用户是否允许访问指定的 API 末端:否
     * @throws NotFoundHttpException
     * @throws UnprocessableEntityHttpException
     */
    public function beforeAction()
    {


        $bodyParams = $request->getBodyParams();

        /* 判断请求参数中框架服务用户标识、框架服务登录标识是否存在 */
        if (!empty($loginId) && !empty($loginTid)) {

            $authKey = Yii::$app->controller->id . '/' . Yii::$app->requestedAction->id;

            // 框架服务权限
            $cmcPermission = Yii::$app->params['cmcPermission'];
            // 返回框架服务权限中的键名(基于权限值、一维数组)
            $cmcPermissionKeys = static::cmcPermissionKeys($cmcPermission, $authKey);

            // 如果框架服务权限为空,则设置默认值:接口权限标识
            if (empty($cmcPermissionKeys)) {
                $cmcPermissionKeys[] = $authKey;
            }

            // 通过框架服务权限标识、框架服务用户标识、框架服务登录标识获取用户权限
            foreach ($cmcPermissionKeys as $cmcPermissionKey) {
                $userAuth = static::userAuth($cmcPermissionKey, $loginId, $loginTid);
                /* 当前用户是否允许访问指定的 API 末端 */
                if ($userAuth['data']['user_auth'] === true) {
                    break;
                }
            }

            /* 权限标识(当前用户是否允许访问指定的 API 末端,例外) */
            $exceptionAuthKey = Yii::$app->params['exceptionAuthKey'];

            /* 当前用户是否允许访问指定的 API 末端 */
            if (!in_array($authKey, $exceptionAuthKey) && $userAuth['data']['user_auth'] === false) {
                throw new ForbiddenHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201012'), ['requested_route' => $authKey])), 201012);
            }

            $groupInfo = $userAuth['data']['group_info'];
            $userInfo = $userAuth['data']['user_info'];

            /* 判断请求参数中来源租户ID是否存在 */
            if (!empty($bodyParams['source_group_id'])) {
                /* 判断请求参数中来源租户ID是否等于用户的租户ID */
                if ($bodyParams['source_group_id'] != $groupInfo['group_id']) {
                    throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201009'), ['source_group_id' => $bodyParams['source_group_id']])), 201009);
                }
                /* 判断请求参数中租户ID是否存在 */
                if (empty($get['group_id'])) {
                    throw new UnprocessableEntityHttpException(Yii::t('error', '201007'), 201007);
                }
            } else {
                /* 判断请求参数中租户ID是否存在 */
                if (!empty($get['group_id'])) {
                    /* 判断请求参数中租户ID是否等于用户的租户ID */
                    if ($get['group_id'] != $groupInfo['group_id']) {
                        throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201008'), ['group_id' => $get['group_id']])), 201008);
                    }
                } else {
                    $get['group_id'] = $groupInfo['group_id'];
                }
            }

            Yii::$app->params['groupId'] = $get['group_id'];
            Yii::$app->params['groupName'] = $groupInfo['group_name'];

            $redisCmcConsoleUser = new RedisCmcConsoleUser();
            $redisCmcConsoleUserResult = $redisCmcConsoleUser->initSync(['group_id' => $groupInfo['group_id']], $loginId, $loginTid);
            if ($redisCmcConsoleUserResult === false) {
                throw new NotFoundHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201041'), ['id' => $loginId])), 201041);
            }

            $redisCmcConsoleUserItem = $redisCmcConsoleUser::find()->where(['id' => $userInfo['id'], 'group_id' => Yii::$app->params['groupId']])->one();

            /* 如果资源不存在,则插入;否则更新 */
            $redisCmcConsoleUserAttributes = [
                'id' => $userInfo['id'],
                'group_id' => $groupInfo['group_id'],
                'login_name' => $userInfo['login_name'],
                'user_token' => $userInfo['user_token'],
                'user_nick' => $userInfo['user_nick'],
                'user_pic' => $userInfo['user_pic'],
                'user_mobile' => $userInfo['user_mobile'] ? $userInfo['user_mobile'] : '',
                'user_email' => $userInfo['user_email'] ? $userInfo['user_email'] : '',
                'user_sex' => $userInfo['user_sex'],
                'user_type' => $userInfo['user_type'],
                'user_birthday' => $userInfo['user_birthday'],
                'user_chat_id' => $userInfo['user_chat_id'] ? $userInfo['user_chat_id'] : '',
                'is_open' => $userInfo['is_open'],
                'add_time' => $userInfo['add_time'],
                'update_time' => $userInfo['update_time'],
                'im_identity' => md5($groupInfo['group_id'] . $userInfo['login_name']),
            ];
            if (!isset($redisCmcConsoleUserItem)) {
                $redisCmcConsoleUser->attributes = $redisCmcConsoleUserAttributes;
                $redisCmcConsoleUser->insert();
                // 设置用户身份为已认证
                Yii::$app->user->setIdentity($redisCmcConsoleUser);
            } else {
                $redisCmcConsoleUserItem->attributes = $redisCmcConsoleUserAttributes;
                $redisCmcConsoleUserItem->save();
                // 设置用户身份为已认证
                Yii::$app->user->setIdentity($redisCmcConsoleUserItem);
            }
        }
    }

    /**
     * 返回用户权限
     *
     * @param string $authKey 权限标识
     * @param string $loginId 用户标识
     * @param string $loginTid 登录标识
     *
     * @return array
     *
     * @throws ServerErrorHttpException 如果响应状态码不等于20x
     * @throws HttpException 如果登录超时
     */
    public static function userAuth($authKey, $loginId, $loginTid)
    {
        // 通过框架服务权限标识、框架服务用户标识、框架服务登录标识获取用户权限
        $httpCmcConsoleUserAuth = new HttpCmcConsoleUserAuth();
        $userAuth = $httpCmcConsoleUserAuth->getUserAuth($authKey, $loginId, $loginTid);
        if ($userAuth === false) {
            if ($httpCmcConsoleUserAuth->hasErrors()) {
                $firstError = '';
                foreach ($httpCmcConsoleUserAuth->getFirstErrors() as $message) {
                    $firstError = $message;
                    break;
                }
                throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201002'), ['first_error' => $firstError])), 201002);
            } elseif (!$httpCmcConsoleUserAuth->hasErrors()) {
                throw new ServerErrorHttpException('Framework Service Console HTTP request fail for unknown reasons.');
            }
        }

        /* 未登录 */
        if ($userAuth['data']['login_status'] === false) {
            throw new HttpException(302, Yii::t('error', '201006'), 201003);
        }

        return $userAuth;
    }

    /**
     * 返回框架服务权限中的键名(基于权限值、一维数组)
     *
     * @param array $array 框架服务权限
     * @param string $needle 待搜索的值
     * 格式如下:plan-config-column-user/index
     *
     * @return array
     * 格式如下:
     * ['plan/create-permission-button', 'plan/have-permission-button']
     *
     */
    public static function cmcPermissionKeys($array, $needle)
    {
        $keys = [];
        foreach($array as $k => $v) {
            if (is_array($v)) {
                if (in_array($needle, $v)) {
                    $keys[] = $k;
                }
                $keys = array_merge($keys, static::cmcPermissionKeys($v, $needle));
            }
        }
        return $keys;
    }

}


17. Call the interface. The interface’s permission identifier is: plan-config-column-user/index. At this point, the key name in the framework service permissions is: [‘plan/create-permission-button’, ‘plan/have-permission-button’]. Since both key names are checked in the current user’s role permission configuration, only 1 authorization request will be executed, as shown in Figure 9.

Call the interface. The interface's permission identifier is: plan-config-column-user/index. At this point, the key name in the framework service permissions is: ['plan/create-permission-button', 'plan/have-permission-button']. Since both key names are checked in the current user's role permission configuration, only 1 authorization request will be executed.
Figure 9

18. Call the interface. The interface’s permission identifier is: plan-config-column-user/index. At this point, the key name in the framework service permissions is: [‘plan/create-permission-button’, ‘plan/have-permission-button’]. Since only the second key name is checked in the current user’s role permission configuration, 2 authorization requests will be executed, as shown in Figure 10 and Figure 11.

Call the interface. The interface's permission identifier is: plan-config-column-user/index. At this point, the key name in the framework service permissions is: ['plan/create-permission-button', 'plan/have-permission-button']. Since only the second key name is checked in the current user's role permission configuration.
Figure 10

Call the interface. The interface's permission identifier is: plan-config-column-user/index. At this point, the key name in the framework service permissions is: ['plan/create-permission-button', 'plan/have-permission-button']. Since only the second key name is checked in the current user's role permission configuration, 2 authorization requests will be executed.
Figure 11

19. Call the interface. The interface’s permission identifier is: plan-config-column-user/index. At this point, the key name in the framework service permissions is: [‘plan/create-permission-button’, ‘plan/have-permission-button’]. Since neither of the 2 key names is checked in the current user’s role permission configuration, 2 authorization requests will be executed, and it will prompt authorization failure, as shown in Figure 12, Figure 13, and Figure 14.

Call the interface. The interface's permission identifier is: plan-config-column-user/index. At this point, the key name in the framework service permissions is: ['plan/create-permission-button', 'plan/have-permission-button']. Since neither of the 2 key names is checked in the current user's role permission configuration.
Figure 12

2 authorization requests will be executed.
Figure 13

 

Prompts authorization failure.
Figure 14

20. Call the interface. The interface’s permission identifier is: plan-config-column-user/index. At this point, the key name in the framework service permissions is: [‘plan/create-permission-button’, ‘plan/have-permission-button’]. Since only the first key name is checked in the current user’s role permission configuration, the execution flow is consistent with step 17.

21. The design principles of permissions are summarized as follows:
(1) The isolation of permissions (four levels) and menus (two levels) ensures flexible handling when the menu display structure does not match the permission structure.
(2) To a certain extent, permissions and menus need to maintain a certain correspondence (hierarchy and names should be kept consistent as much as possible) to resolve the following situation: when a user has the display for a menu, such as the menu: Topics pending review, but does not have the corresponding permission category for the interface: Topics pending review (get topic list) in the permissions, a prompt will pop up directly: No interface permission. At this point, deployment implementers can intuitively check the corresponding permissions in the permission structure based on the menu structure.
(3) When dividing interface categories, it is necessary to ensure that the dependency relationships between interfaces in the same category are fully satisfied. For example: in the permission category to which the interface: Edit topic belongs, there must be other interfaces that the Edit topic interface depends on, such as (interface: Get topic column personnel configuration list (required when creating, editing, and updating a topic)).
(4) The interface: Edit topic exists on both the desktop and mobile terminals. Whether it is necessary to divide the interfaces on the two terminals into different categories. Final decision: since the interface routes have been clearly distinguished, their categories should also be clearly distinguished. The overall structure of permissions is clearer.
(5) The structure of permissions is in the program’s configuration file, formatted as a four-dimensional array.
(6) The same interface may belong to more than one permission category. For example: Get topic column personnel configuration list (required when creating, editing, and updating a topic) exists in both the New topic and Update topic categories. When this happens, the CMC framework interface is called sequentially based on the permission category identifiers until one with a matching permission category identifier is found. Or, if it reaches the end without finding a permission category identifier, it responds that there is no permission for the corresponding interface. Note: Subsequent CMC frameworks need to support permission identifiers in array format to avoid multiple calls to the CMC framework interface.
(7) When calling an interface, confirming its category permission identifier involves getting the array key of its parent dimension. If the permission category it belongs to is empty, the default value is set to the interface’s own permission identifier.

关于作者 · 持续学习与技术实践

我是一名拥有 15 年以上开发经验的技术从业者,自 2013 年起持续运营个人技术博客,记录工作与个人项目中遇到的真实问题,以及解决问题过程中的探索、实践和思考。

除了技术写作,我也在持续开发和维护自己的独立项目,探索新技术和新工具在实际场景中的应用。我始终相信,没有不值得去解决的问题,也没有不值得去学习的技术。

如果这篇文章对你有所帮助,欢迎浏览博客中的其他文章,也欢迎交流技术经验与想法。

关于我  ·  GitHub  ·  邮件联系