diff --git a/README.md b/README.md index fc5872a..511b4b6 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # kafka可视化管理平台 一款轻量级的kafka可视化管理平台,安装配置快捷、简单易用。 为了开发的省事,没有国际化支持,页面只支持中文展示。 -用过rocketmq-console吧,对,前端展示风格跟那个有点类似。 +用过rocketmq-console(rocketmq-dashboard)吧,对,前端展示风格跟那个有点类似。 ## 页面预览 如果github能查看图片的话,可以点击[查看菜单页面](./document/overview/概览.md),查看每个页面的样子 @@ -25,11 +25,11 @@ v1.0.6版本之前,如果kafka集群启用了ACL,但是控制台没看到Acl ![功能特性](./document/img/功能特性.png) ## 安装包下载 -点击下载(v1.0.7版本):[kafka-console-ui.zip](https://github.com/xxd763795151/kafka-console-ui/releases/download/v1.0.7/kafka-console-ui.zip) +点击下载(v1.0.8版本):[kafka-console-ui.zip](https://github.com/xxd763795151/kafka-console-ui/releases/download/v1.0.8/kafka-console-ui.zip) 如果安装包下载的比较慢,可以查看下面的源码打包说明,把代码下载下来,本地快速打包. -github下载慢也可以试试从gitee下载,点击下载[gitee来源kafka-console-ui.zip](https://gitee.com/xiaodong_xu/kafka-console-ui/releases/download/v1.0.7/kafka-console-ui.zip) +github下载慢也可以试试从gitee下载,点击下载[gitee来源kafka-console-ui.zip](https://gitee.com/xiaodong_xu/kafka-console-ui/releases/download/v1.0.8/kafka-console-ui.zip) ## 快速使用 ### Windows @@ -79,11 +79,23 @@ sh bin/shutdown.sh 如果需要本地开发,开发环境配置查看:[本地开发](./document/develop/开发配置.md) ## 登录认证和权限 -目前主分支不支持登录认证,感谢@dongyinuo 同学开发了一版支持登录认证,及相关的按钮权限(主要有两个角色:管理员和普通开发人员)。 +1.0.7版本及之前,主分支不支持登录认证,感谢@dongyinuo 同学开发了一版支持登录认证,及相关的按钮权限(主要有两个角色:管理员和普通开发人员)。 在分支:feature/dongyinuo/20220501/devops 上。 如果有需要使用管理台登录认证的,可以切换到这个分支上进行打包,打包方式看 源码打包 说明。 默认登录账户:admin/kafka-console-ui521 +目前最新版本主分支已增加登录认证、用户、角色等权限配置,如需开启登录认证,修改配置文件config/application.yml: auth.enable=true(默认 false),如下: +```yaml +# 权限认证设置,设置为true,需要先登录才能访问 +auth: + enable: true + # 登录用户token的过期时间,单位:小时 + expire-hours: 24 +``` +默认有两个登录用户:super-admin/123465,admin/123456,登录成功后在个人设置修改密码。super-admin和admin的唯一区别是super-admin可以增加删除用户,admin不能。如果觉得不合适,请在用户菜单下删除相关用户或角色自行创建合适的角色或用户。 +注意:不开启登录认证,页面不显示用户菜单,正常现象。 + + ## DockerCompose部署 感谢@wdkang123 同学分享的部署方式,如果有需要请查看[DockerCompose部署方式](./document/deploy/docker部署.md) diff --git a/bin/shutdown.sh b/bin/shutdown.sh index 8d15dd6..fb68f55 100644 --- a/bin/shutdown.sh +++ b/bin/shutdown.sh @@ -1,7 +1,7 @@ #!/bin/bash -SCRIPT_DIR=`dirname $0` -PROJECT_DIR="$SCRIPT_DIR/.." +SCRIPT_DIR=$(dirname "`pwd`/$0") +PROJECT_DIR=`dirname "$SCRIPT_DIR"` # 不要修改进程标记,作为进程属性关闭使用 PROCESS_FLAG="kafka-console-ui-process-flag:${PROJECT_DIR}" pkill -f $PROCESS_FLAG diff --git a/bin/start.sh b/bin/start.sh index f09352c..500bf77 100644 --- a/bin/start.sh +++ b/bin/start.sh @@ -3,8 +3,8 @@ # 设置jvm堆大小及栈大小,栈大小最少设置为256K,不要小于这个值,比如设置为128,太小了 JAVA_MEM_OPTS="-Xmx512m -Xms512m -Xmn256m -Xss256k" -SCRIPT_DIR=`dirname $0` -PROJECT_DIR="$SCRIPT_DIR/.." +SCRIPT_DIR=$(dirname "`pwd`/$0") +PROJECT_DIR=`dirname "$SCRIPT_DIR"` CONF_FILE="$PROJECT_DIR/config/application.yml" TARGET="$PROJECT_DIR/lib/kafka-console-ui.jar" diff --git a/pom.xml b/pom.xml index 5755458..f794436 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.xuxd kafka-console-ui - 1.0.7 + 1.0.8 kafka-console-ui Kafka console manage ui @@ -174,26 +174,26 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + maven-compiler-plugin @@ -201,6 +201,8 @@ ${compiler.version} ${compiler.version} ${project.build.sourceEncoding} + + @@ -225,7 +227,7 @@ npm - + install --registry=https://registry.npm.taobao.org diff --git a/src/main/java/com/xuxd/kafka/console/controller/AclUserController.java b/src/main/java/com/xuxd/kafka/console/controller/AclUserController.java index 932d68a..04054fd 100644 --- a/src/main/java/com/xuxd/kafka/console/controller/AclUserController.java +++ b/src/main/java/com/xuxd/kafka/console/controller/AclUserController.java @@ -54,12 +54,12 @@ public class AclUserController { @Permission("acl:sasl-scram:detail") @GetMapping("/detail") - public Object getUserDetail(@RequestParam String username) { + public Object getUserDetail(@RequestParam("username") String username) { return aclService.getUserDetail(username); } @GetMapping("/scram") - public Object getSaslScramUserList(@RequestParam(required = false) String username) { + public Object getSaslScramUserList(@RequestParam(required = false, name = "username") String username) { AclEntry entry = new AclEntry(); entry.setPrincipal(StringUtils.isNotBlank(username) ? username : null); return aclService.getSaslScramUserList(entry); diff --git a/src/main/java/com/xuxd/kafka/console/controller/ConsumerController.java b/src/main/java/com/xuxd/kafka/console/controller/ConsumerController.java index c5a7320..a18c225 100644 --- a/src/main/java/com/xuxd/kafka/console/controller/ConsumerController.java +++ b/src/main/java/com/xuxd/kafka/console/controller/ConsumerController.java @@ -45,19 +45,19 @@ public class ConsumerController { @Permission("group:del") @DeleteMapping("/group") - public Object deleteConsumerGroup(@RequestParam String groupId) { + public Object deleteConsumerGroup(@RequestParam("groupId") String groupId) { return consumerService.deleteConsumerGroup(groupId); } @Permission("group:client") @GetMapping("/member") - public Object getConsumerMembers(@RequestParam String groupId) { + public Object getConsumerMembers(@RequestParam("groupId") String groupId) { return consumerService.getConsumerMembers(groupId); } @Permission("group:consumer-detail") @GetMapping("/detail") - public Object getConsumerDetail(@RequestParam String groupId) { + public Object getConsumerDetail(@RequestParam("groupId") String groupId) { return consumerService.getConsumerDetail(groupId); } @@ -114,19 +114,19 @@ public class ConsumerController { } @GetMapping("/topic/list") - public Object getSubscribeTopicList(@RequestParam String groupId) { + public Object getSubscribeTopicList(@RequestParam("groupId") String groupId) { return consumerService.getSubscribeTopicList(groupId); } @Permission({"topic:consumer-detail"}) @GetMapping("/topic/subscribed") - public Object getTopicSubscribedByGroups(@RequestParam String topic) { + public Object getTopicSubscribedByGroups(@RequestParam("topic") String topic) { return consumerService.getTopicSubscribedByGroups(topic); } @Permission("group:offset-partition") @GetMapping("/offset/partition") - public Object getOffsetPartition(@RequestParam String groupId) { + public Object getOffsetPartition(@RequestParam("groupId") String groupId) { return consumerService.getOffsetPartition(groupId); } } diff --git a/src/main/java/com/xuxd/kafka/console/controller/OperationController.java b/src/main/java/com/xuxd/kafka/console/controller/OperationController.java index 4daf6bc..6847b45 100644 --- a/src/main/java/com/xuxd/kafka/console/controller/OperationController.java +++ b/src/main/java/com/xuxd/kafka/console/controller/OperationController.java @@ -42,7 +42,7 @@ public class OperationController { } @DeleteMapping("/sync/alignment") - public Object deleteAlignment(@RequestParam Long id) { + public Object deleteAlignment(@RequestParam("id") Long id) { return operationService.deleteAlignmentById(id); } diff --git a/src/main/java/com/xuxd/kafka/console/controller/TopicController.java b/src/main/java/com/xuxd/kafka/console/controller/TopicController.java index 318630a..d41ae1f 100644 --- a/src/main/java/com/xuxd/kafka/console/controller/TopicController.java +++ b/src/main/java/com/xuxd/kafka/console/controller/TopicController.java @@ -35,7 +35,7 @@ public class TopicController { @Permission("topic:load") @GetMapping("/list") - public Object getTopicList(@RequestParam(required = false) String topic, @RequestParam String type) { + public Object getTopicList(@RequestParam(required = false, name = "topic") String topic, @RequestParam("type") String type) { return topicService.getTopicList(topic, TopicType.valueOf(type.toUpperCase())); } @@ -47,7 +47,7 @@ public class TopicController { @Permission("topic:partition-detail") @GetMapping("/partition") - public Object getTopicPartitionInfo(@RequestParam String topic) { + public Object getTopicPartitionInfo(@RequestParam("topic") String topic) { return topicService.getTopicPartitionInfo(topic.trim()); } @@ -76,7 +76,7 @@ public class TopicController { } @GetMapping("/replica/assignment") - public Object getCurrentReplicaAssignment(@RequestParam String topic) { + public Object getCurrentReplicaAssignment(@RequestParam("topic") String topic) { return topicService.getCurrentReplicaAssignment(topic); } @@ -94,7 +94,7 @@ public class TopicController { @Permission("topic:send-count") @GetMapping("/send/stats") - public Object sendStats(@RequestParam String topic) { + public Object sendStats(@RequestParam("topic") String topic) { return topicService.sendStats(topic); } } diff --git a/src/main/java/com/xuxd/kafka/console/controller/UserManageController.java b/src/main/java/com/xuxd/kafka/console/controller/UserManageController.java index 6af2def..c158d43 100644 --- a/src/main/java/com/xuxd/kafka/console/controller/UserManageController.java +++ b/src/main/java/com/xuxd/kafka/console/controller/UserManageController.java @@ -73,14 +73,14 @@ public class UserManageController { @Permission("user-manage:role:del") @ControllerLog("删除角色") @DeleteMapping("/role") - public Object deleteRole(@RequestParam Long id) { + public Object deleteRole(@RequestParam("id") Long id) { return userManageService.deleteRole(id); } @Permission("user-manage:user:del") @ControllerLog("删除用户") @DeleteMapping("/user") - public Object deleteUser(@RequestParam Long id) { + public Object deleteUser(@RequestParam("id") Long id) { return userManageService.deleteUser(id); } diff --git a/src/main/java/com/xuxd/kafka/console/dao/init/SqlParse.java b/src/main/java/com/xuxd/kafka/console/dao/init/SqlParse.java index 1ce6975..f224d13 100644 --- a/src/main/java/com/xuxd/kafka/console/dao/init/SqlParse.java +++ b/src/main/java/com/xuxd/kafka/console/dao/init/SqlParse.java @@ -1,15 +1,12 @@ package com.xuxd.kafka.console.dao.init; -import com.google.common.io.Files; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.util.ResourceUtils; import scala.collection.mutable.StringBuilder; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.charset.Charset; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -22,7 +19,7 @@ import java.util.Map; @Slf4j public class SqlParse { - private final String FILE = "classpath:db/data-h2.sql"; + private final String FILE = "db/data-h2.sql"; private final Map> sqlMap = new HashMap<>(); @@ -37,8 +34,7 @@ public class SqlParse { String table = null; try { - File file = ResourceUtils.getFile(FILE); - List lines = Files.readLines(file, Charset.forName("UTF-8")); + List lines = getSqlLines(); for (String str : lines) { if (StringUtils.isNotEmpty(str)) { if (str.indexOf("start--") > 0) { @@ -61,9 +57,7 @@ public class SqlParse { } } } - } catch (FileNotFoundException e) { - throw new RuntimeException(e); - } catch (IOException e) { + } catch (Exception e) { throw new RuntimeException(e); } } @@ -82,4 +76,21 @@ public class SqlParse { private boolean isSql(String str) { return StringUtils.isNotEmpty(str) && str.startsWith("insert"); } + + private List getSqlLines() throws Exception { +// File file = ResourceUtils.getFile(FILE); +// List lines = Files.readLines(file, Charset.forName("UTF-8")); + List lines = new ArrayList<>(); + try (InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(FILE)) { + try (InputStreamReader inputStreamReader = new InputStreamReader(inputStream)) { + try (BufferedReader reader = new BufferedReader(inputStreamReader)) { + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + } + } + } + return lines; + } } diff --git a/src/main/java/com/xuxd/kafka/console/filter/AuthFilter.java b/src/main/java/com/xuxd/kafka/console/filter/AuthFilter.java index 6137eb3..6bd2a06 100644 --- a/src/main/java/com/xuxd/kafka/console/filter/AuthFilter.java +++ b/src/main/java/com/xuxd/kafka/console/filter/AuthFilter.java @@ -44,6 +44,10 @@ public class AuthFilter implements Filter { String accessToken = request.getHeader(TOKEN_HEADER); String requestURI = request.getRequestURI(); + if (isResourceRequest(requestURI)) { + filterChain.doFilter(servletRequest, servletResponse); + return; + } if (requestURI.startsWith(AUTH_URI_PREFIX)) { filterChain.doFilter(servletRequest, servletResponse); return; @@ -63,8 +67,12 @@ public class AuthFilter implements Filter { try { CredentialsContext.set(credentials); filterChain.doFilter(servletRequest, servletResponse); - }finally { + } finally { CredentialsContext.remove(); } } + + private boolean isResourceRequest(String requestURI) { + return requestURI.contains(".") || requestURI.equals("/"); + } } diff --git a/ui/src/utils/request.js b/ui/src/utils/request.js index 859fecb..115b630 100644 --- a/ui/src/utils/request.js +++ b/ui/src/utils/request.js @@ -22,11 +22,11 @@ const errorHandler = (error) => { }); Router.push({ path: "/login-page" }); } else if (error.response.status == 403) { - // const data = error.response.data; - // notification.error({ - // message: error.response.status, - // description: data.msg, - // }); + const data = error.response.data; + notification.error({ + message: error.response.status, + description: data.msg, + }); } else { const data = error.response.data; notification.error({ diff --git a/ui/src/views/group/Group.vue b/ui/src/views/group/Group.vue index b38f600..acc66ba 100644 --- a/ui/src/views/group/Group.vue +++ b/ui/src/views/group/Group.vue @@ -160,6 +160,7 @@ import Member from "@/views/group/Member"; import ConsumerDetail from "@/views/group/ConsumerDetail"; import AddSupscription from "@/views/group/AddSupscription"; import OffsetTopicPartition from "@/views/group/OffsetTopicPartition"; +import { isAuthorized } from "@/utils/auth"; export default { name: "ConsumerGroup", @@ -235,6 +236,9 @@ export default { }); }, openConsumerMemberDialog(groupId) { + if (!isAuthorized("group:client")) { + return; + } this.showConsumerGroupDialog = true; this.selectDetail.resourceName = groupId; }, diff --git a/ui/src/views/topic/Topic.vue b/ui/src/views/topic/Topic.vue index 0ad0a9e..2a1dfed 100644 --- a/ui/src/views/topic/Topic.vue +++ b/ui/src/views/topic/Topic.vue @@ -1,5 +1,5 @@