Kaynağa Gözat

优化菜单管理

zhou-hao 3 yıl önce
ebeveyn
işleme
2a96d6896d

+ 47 - 0
jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/MenuButtonInfo.java

@@ -0,0 +1,47 @@
+package org.jetlinks.community.auth.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.collections4.CollectionUtils;
+
+import java.util.*;
+import java.util.function.BiPredicate;
+
+@Getter
+@Setter
+public class MenuButtonInfo {
+
+    @Schema(description = "按钮ID")
+    private String id;
+
+    @Schema(description = "按钮名称")
+    private String name;
+
+    @Schema(description = "权限信息")
+    private List<PermissionInfo> permissions;
+
+    @Schema(description = "其他配置")
+    private Map<String, Object> options;
+
+    public boolean hasPermission(BiPredicate<String, Collection<String>> predicate) {
+        if (CollectionUtils.isEmpty(permissions)) {
+            return true;
+        }
+
+        for (PermissionInfo permission : permissions) {
+            if (!predicate.test(permission.getPermission(), permission.getActions())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static MenuButtonInfo of(String id, String name, String permission, String... actions) {
+        MenuButtonInfo info = new MenuButtonInfo();
+        info.setId(id);
+        info.setName(name);
+        info.setPermissions(Arrays.asList(PermissionInfo.of(permission, new HashSet<>(Arrays.asList(actions)))));
+        return info;
+    }
+}

+ 90 - 6
jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/MenuEntity.java

@@ -1,29 +1,41 @@
 package org.jetlinks.community.auth.entity;
 
+import io.swagger.v3.oas.annotations.Hidden;
+import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Getter;
 import lombok.Setter;
+import org.apache.commons.collections4.CollectionUtils;
 import org.hswebframework.ezorm.rdb.mapping.annotation.ColumnType;
 import org.hswebframework.ezorm.rdb.mapping.annotation.Comment;
+import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue;
+import org.hswebframework.ezorm.rdb.mapping.annotation.JsonCodec;
 import org.hswebframework.web.api.crud.entity.GenericTreeSortSupportEntity;
+import org.jetlinks.community.auth.web.request.AuthorizationSettingDetail;
 
 import javax.persistence.Column;
 import javax.persistence.Index;
 import javax.persistence.Table;
 import java.sql.JDBCType;
-import java.util.List;
+import java.util.*;
+import java.util.function.BiPredicate;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 /**
+ * 菜单定义实体类
+ *
  * @author wangzheng
  * @since 1.0
  */
 @Getter
 @Setter
 @Table(name = "s_menu", indexes = {
-        @Index(name = "idx_menu_path", columnList = "path")
+    @Index(name = "idx_menu_path", columnList = "path")
 })
 public class MenuEntity
-        extends GenericTreeSortSupportEntity<String> {
+    extends GenericTreeSortSupportEntity<String> {
 
+    @Schema(description = "名称")
     @Comment("菜单名称")
     @Column(length = 32)
     private String name;
@@ -31,29 +43,101 @@ public class MenuEntity
     @Comment("描述")
     @Column
     @ColumnType(jdbcType = JDBCType.CLOB)
+    @Schema(description = "描述")
     private String describe;
 
+    @Hidden
+    @Deprecated
     @Comment("权限表达式")
     @Column(name = "permission_expression", length = 256)
     private String permissionExpression;
 
     @Comment("菜单对应的url")
     @Column(length = 512)
+    @Schema(description = "URL,路由")
     private String url;
 
     @Comment("图标")
     @Column(length = 256)
+    @Schema(description = "图标")
     private String icon;
 
     @Comment("状态")
     @Column
     @ColumnType(jdbcType = JDBCType.SMALLINT)
+    @Schema(description = "状态,0为禁用,1为启用")
+    @DefaultValue("1")
     private Byte status;
+
+    @Schema(description = "默认权限信息")
+    @Column
+    @JsonCodec
+    @ColumnType(jdbcType = JDBCType.LONGVARCHAR, javaType = String.class)
+    private List<PermissionInfo> permissions;
+
+    @Schema(description = "按钮定义信息")
+    @Column
+    @JsonCodec
+    @ColumnType(jdbcType = JDBCType.LONGVARCHAR, javaType = String.class)
+    private List<MenuButtonInfo> buttons;
+
+    @Schema(description = "其他配置信息")
+    @Column
+    @JsonCodec
+    @ColumnType(jdbcType = JDBCType.LONGVARCHAR, javaType = String.class)
+    private Map<String, Object> options;
+
     //子菜单
+    @Schema(description = "子菜单")
     private List<MenuEntity> children;
 
-    @Override
-    public List<MenuEntity> getChildren() {
-        return children;
+    public MenuEntity copy(Predicate<MenuButtonInfo> buttonPredicate) {
+        MenuEntity entity = this.copyTo(new MenuEntity());
+
+        if (CollectionUtils.isEmpty(entity.getButtons())) {
+            return entity;
+        }
+        entity.setButtons(
+            entity
+                .getButtons()
+                .stream()
+                .filter(buttonPredicate)
+                .collect(Collectors.toList())
+        );
+        return entity;
+    }
+
+    public boolean hasPermission(BiPredicate<String, Collection<String>> predicate) {
+        if (CollectionUtils.isEmpty(permissions) && CollectionUtils.isEmpty(buttons)) {
+            return false;
+        }
+        //有权限信息
+        if (CollectionUtils.isNotEmpty(permissions)) {
+            for (PermissionInfo permission : permissions) {
+                if (!predicate.test(permission.getPermission(), permission.getActions())) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        //有任意按钮信息
+        if (CollectionUtils.isNotEmpty(buttons)) {
+            for (MenuButtonInfo button : buttons) {
+                if (button.hasPermission(predicate)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public Optional<MenuButtonInfo> getButton(String id) {
+        if (buttons == null) {
+            return Optional.empty();
+        }
+        return buttons
+            .stream()
+            .filter(button -> Objects.equals(button.getId(), id))
+            .findAny();
     }
 }

+ 58 - 0
jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/MenuView.java

@@ -0,0 +1,58 @@
+package org.jetlinks.community.auth.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.hswebframework.web.api.crud.entity.GenericTreeSortSupportEntity;
+import org.hswebframework.web.bean.FastBeanCopier;
+
+import java.util.List;
+import java.util.Map;
+
+@Getter
+@Setter
+public class MenuView extends GenericTreeSortSupportEntity<String> {
+
+    @Schema(description = "菜单名称")
+    private String name;
+
+    @Schema(description = "图标")
+    private String icon;
+
+    @Schema(description = "URL")
+    private String url;
+
+    @Schema(description = "父节点")
+    private String parentId;
+
+    @Schema(description = "按钮")
+    private List<ButtonView> buttons;
+
+    @Schema(description = "其他配置")
+    private Map<String, Object> options;
+
+    @Schema(description = "子节点")
+    private List<MenuView> children;
+
+    @Getter
+    @Setter
+    @AllArgsConstructor(staticName = "of")
+    @NoArgsConstructor
+    public static class ButtonView{
+
+        @Schema(description = "按钮ID")
+        private String id;
+
+        @Schema(description = "按钮名称")
+        private String name;
+
+        @Schema(description = "其他配置")
+        private Map<String,Object> options;
+    }
+
+    public static MenuView of(MenuEntity entity){
+        return FastBeanCopier.copy(entity,new MenuView());
+    }
+}

+ 23 - 0
jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/PermissionInfo.java

@@ -0,0 +1,23 @@
+package org.jetlinks.community.auth.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.Set;
+
+@Getter
+@Setter
+@AllArgsConstructor(staticName = "of")
+@NoArgsConstructor
+public class PermissionInfo {
+
+    @Schema(description = "权限ID")
+    private String permission;
+
+    @Schema(description = "权限操作")
+    private Set<String> actions;
+
+}

+ 137 - 39
jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/web/MenuController.java

@@ -1,31 +1,37 @@
 package org.jetlinks.community.auth.web;
 
-import io.swagger.v3.oas.annotations.Hidden;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.AllArgsConstructor;
 import org.hswebframework.web.api.crud.entity.TreeSupportEntity;
 import org.hswebframework.web.authorization.Authentication;
-import org.hswebframework.web.authorization.AuthenticationUtils;
 import org.hswebframework.web.authorization.annotation.Authorize;
 import org.hswebframework.web.authorization.annotation.Resource;
+import org.hswebframework.web.authorization.annotation.ResourceAction;
 import org.hswebframework.web.authorization.exception.UnAuthorizedException;
 import org.hswebframework.web.crud.service.ReactiveCrudService;
 import org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController;
+import org.jetlinks.community.auth.entity.MenuButtonInfo;
 import org.jetlinks.community.auth.entity.MenuEntity;
+import org.jetlinks.community.auth.entity.MenuView;
+import org.jetlinks.community.auth.service.AuthorizationSettingDetailService;
 import org.jetlinks.community.auth.service.DefaultMenuService;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.jetlinks.community.auth.web.request.MenuGrantRequest;
 import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
-import java.util.*;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 /**
  * 菜单管理
+ *
  * @author wangzheng
  * @since 1.0
  */
@@ -33,27 +39,140 @@ import java.util.stream.Collectors;
 @RequestMapping("/menu")
 @Authorize
 @Resource(id = "menu", name = "菜单管理", group = "system")
-@Hidden
+@Tag(name = "菜单管理")
+@AllArgsConstructor
 public class MenuController implements ReactiveServiceCrudController<MenuEntity, String> {
 
-    @Autowired
-    private DefaultMenuService defaultMenuService;
+    private final DefaultMenuService defaultMenuService;
+
+    private final AuthorizationSettingDetailService settingService;
 
     @Override
     public ReactiveCrudService<MenuEntity, String> getService() {
         return defaultMenuService;
     }
 
-    public Collection<MenuEntity> predicateUserMenu(Map<String, MenuEntity> menuMap, Authentication autz) {
+    /**
+     * 获取用户自己的菜单列表
+     *
+     * @return 菜单列表
+     */
+    @GetMapping("/user-own/tree")
+    @Authorize(merge = false)
+    @Operation(summary = "获取当前用户可访问的菜单(树结构)")
+    public Flux<MenuView> getUserMenuAsTree() {
+        return this
+            .getUserMenuAsList()
+            .as(MenuController::listToTree);
+    }
+
+
+    @GetMapping("/user-own/list")
+    @Authorize(merge = false)
+    @Operation(summary = "获取当前用户可访问的菜单(列表结构)")
+    public Flux<MenuView> getUserMenuAsList() {
+        return Authentication
+            .currentReactive()
+            .switchIfEmpty(Mono.error(UnAuthorizedException::new))
+            .flatMapMany(autz -> defaultMenuService
+                .createQuery()
+                .where(MenuEntity::getStatus,1)
+                .fetch()
+                .collect(Collectors.toMap(MenuEntity::getId, Function.identity()))
+                .flatMapIterable(menuMap -> MenuController
+                    .convertMenuView(menuMap,
+                                     menu -> "admin".equals(autz.getUser().getUsername()) ||
+                                         menu.hasPermission(autz::hasPermission),
+                                     button -> "admin".equals(autz.getUser().getUsername()) ||
+                                         button.hasPermission(autz::hasPermission)
+                    )));
+    }
+
+    @PutMapping("/_grant")
+    @Operation(summary = "根据菜单进行授权")
+    @ResourceAction(id = "grant", name = "授权")
+    public Mono<Void> grant(@RequestBody Mono<MenuGrantRequest> body) {
+        return Mono
+            .zip(
+                //T1: 当前用户权限信息
+                Authentication.currentReactive(),
+                //T2: 将菜单信息转为授权信息
+                Mono
+                    .zip(body,
+                         defaultMenuService
+                             .createQuery()
+                             .where(MenuEntity::getStatus,1)
+                             .fetch()
+                             .collectList(),
+                         MenuGrantRequest::toAuthorizationSettingDetail
+                    )
+                    .map(Flux::just),
+                //保存授权信息
+                settingService::saveDetail
+            )
+            .flatMap(Function.identity());
+    }
+
+    @GetMapping("/{targetType}/{targetId}/_grant/tree")
+    @ResourceAction(id = "grant", name = "授权")
+    @Operation(summary = "获取菜单授权信息(树结构)")
+    public Flux<MenuView> getGrantInfoTree(@PathVariable String targetType,
+                                           @PathVariable String targetId) {
+
+        return this
+            .getGrantInfo(targetType, targetId)
+            .as(MenuController::listToTree);
+    }
+
+    @GetMapping("/{targetType}/{targetId}/_grant/list")
+    @ResourceAction(id = "grant", name = "授权")
+    @Operation(summary = "获取菜单授权信息(列表结构)")
+    public Flux<MenuView> getGrantInfo(@PathVariable String targetType,
+                                       @PathVariable String targetId) {
+
+        return Mono
+            .zip(
+                //权限设置信息
+                settingService.getSettingDetail(targetType, targetId),
+                //菜单
+                defaultMenuService
+                    .createQuery()
+                    .where(MenuEntity::getStatus,1)
+                    .fetch()
+                    .collectMap(MenuEntity::getId, Function.identity()),
+                (detail, menuMap) -> MenuController
+                    .convertMenuView(menuMap,
+                                     menu -> menu.hasPermission(detail::hasPermission),
+                                     button -> button.hasPermission(detail::hasPermission)
+                    )
+            )
+            .flatMapIterable(Function.identity());
+    }
+
+    private static Flux<MenuView> listToTree(Flux<MenuView> flux) {
+        return flux
+            .collectList()
+            .flatMapIterable(list -> TreeSupportEntity
+                .list2tree(list,
+                           MenuView::setChildren,
+                           (Predicate<MenuView>) n ->
+                               StringUtils.isEmpty(n.getParentId())
+                                   || "-1".equals(n.getParentId())));
+    }
+
+    private static Collection<MenuView> convertMenuView(Map<String, MenuEntity> menuMap,
+                                                        Predicate<MenuEntity> menuPredicate,
+                                                        Predicate<MenuButtonInfo> buttonPredicate) {
         Map<String, MenuEntity> group = new HashMap<>();
         for (MenuEntity menu : menuMap.values()) {
             if (group.containsKey(menu.getId())) {
                 continue;
             }
-            if (autz.getUser().getUsername().equals("admin") || AuthenticationUtils.createPredicate(menu.getPermissionExpression()).test(autz)) {
+            if (menuPredicate.test(menu)) {
                 String parentId = menu.getParentId();
                 MenuEntity parent;
                 group.put(menu.getId(), menu);
+                //有子菜单默认就有父菜单
                 while (!StringUtils.isEmpty(parentId)) {
                     parent = menuMap.get(parentId);
                     if (parent == null) {
@@ -64,33 +183,12 @@ public class MenuController implements ReactiveServiceCrudController<MenuEntity,
                 }
             }
         }
-        List<MenuEntity> list = new ArrayList<>(group.values());
-        Collections.sort(list);
-
-        return list;
+        return group
+            .values()
+            .stream()
+            .map(menu -> MenuView.of(menu.copy(buttonPredicate)))
+            .sorted()
+            .collect(Collectors.toList());
     }
 
-    /**
-     * 获取用户自己的菜单列表
-     * @return 菜单列表
-     */
-    @GetMapping("user-own/tree")
-    @Authorize(merge = false)
-    public Flux<MenuEntity> getUserMenuAsTree() {
-        return Authentication
-                .currentReactive()
-                .switchIfEmpty(Mono.error(UnAuthorizedException::new))
-                .flatMapMany(autz -> defaultMenuService
-                        .createQuery()
-                        .fetch()
-                        .collect(Collectors.toMap(MenuEntity::getId, Function.identity()))
-                        .map(menuMap -> predicateUserMenu(menuMap, autz))
-                        .map(menus -> TreeSupportEntity.list2tree(
-                                menus,
-                                MenuEntity::setChildren,
-                                (Predicate<MenuEntity>) n ->
-                                        StringUtils.isEmpty(n.getParentId())
-                                                || "-1".equals(n.getParentId()))).flatMapMany(Flux::fromIterable));
-
-    }
 }

+ 41 - 4
jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/web/request/AuthorizationSettingDetail.java

@@ -1,5 +1,7 @@
 package org.jetlinks.community.auth.web.request;
 
+import io.swagger.v3.oas.annotations.Hidden;
+import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import org.apache.commons.collections.CollectionUtils;
 import org.hswebframework.web.authorization.Dimension;
@@ -25,56 +27,85 @@ public class AuthorizationSettingDetail {
      * 设置目标类型(维度)标识,如: org, role
      */
     @NotBlank
+    @Schema(description = "权限类型,如: org,openApi")
     private String targetType;
 
     /**
      * 设置目标.
      */
     @NotBlank
+    @Schema(description = "权限类型对应的数据ID")
     private String targetId;
 
     /**
      * 冲突时是否合并
      */
+    @Schema(description = "冲突时是否合并")
     private boolean merge = true;
 
     /**
      * 冲突时优先级
      */
+    @Schema(description = "冲突时合并优先级")
     private int priority = 10;
 
     /**
      * 权限列表
      */
+    @Schema(description = "权限列表")
     private List<PermissionInfo> permissionList;
 
+    public boolean hasPermission(String id, Collection<String> actions) {
+        if (CollectionUtils.isEmpty(permissionList)) {
+            return false;
+        }
+        for (PermissionInfo info : permissionList) {
+            if (Objects.equals(info.getId(), id)) {
+                if (CollectionUtils.isEmpty(actions)) {
+                    return true;
+                }
+                if (CollectionUtils.isNotEmpty(info.getActions())) {
+                    if (info.getActions().containsAll(actions)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
     /**
      * 授权信息
      */
     @Getter
     @Setter
     @EqualsAndHashCode(of = "id")
+    @Generated
     public static class PermissionInfo {
 
         /**
          * 权限ID
          */
         @NotBlank
+        @Schema(description = "权限ID")
         private String id;
 
         /**
          * 授权操作
          */
+        @Schema(description = "允许执行的操作")
         private Set<String> actions;
 
         /**
          * 字段权限
          */
+        @Hidden
         private List<FieldAccess> fieldAccess;
 
         /**
          * 数据权限
          */
+        @Hidden
         private List<DataAccess> dataAccess;
 
         private PermissionInfo unwrap(AuthorizationSettingEntity entity) {
@@ -94,8 +125,8 @@ public class AuthorizationSettingDetail {
                     //字段权限
                     if (DataAccessConfig.DefaultType.DENY_FIELDS.equalsIgnoreCase(access.getType())) {
                         Set<String> fields = Optional.ofNullable(access.getConfig())
-                            .<Set<String>>map(conf -> new HashSet<>((Collection<String>) conf.get("fields")))
-                            .orElseGet(HashSet::new);
+                                                     .<Set<String>>map(conf -> new HashSet<>((Collection<String>) conf.get("fields")))
+                                                     .orElseGet(HashSet::new);
 
                         for (String field : fields) {
                             filedAccessMap
@@ -130,7 +161,7 @@ public class AuthorizationSettingDetail {
                 for (FieldAccess access : fieldAccess) {
                     for (String action : access.getAction()) {
                         group.computeIfAbsent(action, r -> new HashSet<>())
-                            .add(access.name);
+                             .add(access.name);
                     }
                 }
                 for (Map.Entry<String, Set<String>> entry : group.entrySet()) {
@@ -150,6 +181,12 @@ public class AuthorizationSettingDetail {
             entity.setDataAccesses(entities);
         }
 
+        public static PermissionInfo of(String id, Collection<String> actions) {
+            PermissionInfo info = new PermissionInfo();
+            info.setId(id);
+            info.setActions(new HashSet<>(actions));
+            return info;
+        }
     }
 
 
@@ -184,7 +221,7 @@ public class AuthorizationSettingDetail {
         }
 
         public List<DataAccessEntity> toEntity() {
-            if(CollectionUtils.isEmpty(actions)){
+            if (CollectionUtils.isEmpty(actions)) {
                 return Collections.emptyList();
             }
             return actions

+ 97 - 0
jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/web/request/MenuGrantRequest.java

@@ -0,0 +1,97 @@
+package org.jetlinks.community.auth.web.request;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.apache.commons.collections4.CollectionUtils;
+import org.hswebframework.web.api.crud.entity.TreeSupportEntity;
+import org.hswebframework.web.id.IDGenerator;
+import org.jetlinks.community.auth.entity.MenuView;
+import org.jetlinks.community.auth.entity.MenuEntity;
+import org.jetlinks.community.auth.entity.MenuView;
+import org.jetlinks.community.auth.entity.PermissionInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class MenuGrantRequest {
+
+
+    private String targetType;
+
+    private String targetId;
+
+    /**
+     * 冲突时是否合并
+     */
+    @Schema(description = "冲突时是否合并")
+    private boolean merge = true;
+
+    /**
+     * 冲突时优先级
+     */
+    @Schema(description = "冲突时合并优先级")
+    private int priority = 10;
+
+    @Schema(description = "授权的菜单信息")
+    private List<MenuView> menus;
+
+    public AuthorizationSettingDetail toAuthorizationSettingDetail(List<MenuEntity> menuEntities) {
+        Map<String, MenuEntity> menuMap = menuEntities
+            .stream()
+            .collect(Collectors.toMap(MenuEntity::getId, Function.identity()));
+        AuthorizationSettingDetail detail = new AuthorizationSettingDetail();
+        detail.setTargetType(targetType);
+        detail.setTargetId(targetId);
+        detail.setMerge(merge);
+        detail.setPriority(priority);
+
+        List<AuthorizationSettingDetail.PermissionInfo> permissionInfos = new ArrayList<>();
+
+        for (MenuView menu : menus) {
+            //平铺
+            List<MenuView> expand = TreeSupportEntity.expandTree2List(menu, IDGenerator.MD5);
+            for (MenuView menuView : expand) {
+                MenuEntity entity = menuMap.get(menuView.getId());
+                if (entity == null) {
+                    continue;
+                }
+                //自动持有配置的权限
+                if (CollectionUtils.isNotEmpty(entity.getPermissions())) {
+                    for (PermissionInfo permission : entity.getPermissions()) {
+                        permissionInfos.add(AuthorizationSettingDetail.PermissionInfo.of(permission.getPermission(), permission.getActions()));
+                    }
+                }
+
+                if (CollectionUtils.isNotEmpty(menuView.getButtons())) {
+                    for (MenuView.ButtonView button : menuView.getButtons()) {
+                        entity.getButton(button.getId())
+                              .ifPresent(buttonInfo -> {
+                                  if (CollectionUtils.isNotEmpty(buttonInfo.getPermissions())) {
+                                      for (PermissionInfo permission : buttonInfo.getPermissions()) {
+                                          permissionInfos
+                                              .add(AuthorizationSettingDetail.PermissionInfo.of(permission.getPermission(), permission.getActions()));
+                                      }
+
+                                  }
+                              });
+                    }
+                }
+            }
+        }
+        detail.setPermissionList(permissionInfos);
+
+        return detail;
+    }
+
+
+}