diff --git a/pom.xml b/pom.xml
index 8837a45..777db59 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,194 +1,212 @@
- 4.0.0
-
- org.springframework.boot
- spring-boot-starter-parent
- 2.4.10
-
-
- com.xuxd
- kafka-console-ui
- 0.0.1-SNAPSHOT
- kafka-console-ui
- Kafka console manage ui
-
- 1.8
- UTF-8
- 1.8
- 1.8
- ${project.basedir}/ui
- 1.11.0
- 1.8
-
-
-
- org.scala-lang
- scala-library
- 2.13.6
-
-
- org.scala-lang
- scala-compiler
- 2.13.6
-
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.4.10
+
+
+ com.xuxd
+ kafka-console-ui
+ 0.0.1-SNAPSHOT
+ kafka-console-ui
+ Kafka console manage ui
+
+ 1.8
+ UTF-8
+ 1.8
+ 1.8
+ ${project.basedir}/ui
+ 1.11.0
+ 1.8
+
+
+
+ org.scala-lang
+ scala-library
+ 2.13.6
+
+
+ org.scala-lang
+ scala-compiler
+ 2.13.6
+
-
- org.springframework.boot
- spring-boot-starter
-
+
+ org.springframework.boot
+ spring-boot-starter
+
-
- org.springframework.boot
- spring-boot-starter-web
-
+
+ org.springframework.boot
+ spring-boot-starter-web
+
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
-
- org.apache.kafka
- kafka-clients
- 2.8.0
-
+
+ org.apache.kafka
+ kafka-clients
+ 2.8.0
+
-
-
- org.apache.commons
- commons-lang3
- 3.12.0
-
+
+
+ org.apache.commons
+ commons-lang3
+ 3.12.0
+
-
- com.google.guava
- guava
- 23.0
-
+
+ com.google.guava
+ guava
+ 23.0
+
-
- org.projectlombok
- lombok
- 1.18.20
- provided
-
-
+
+ org.projectlombok
+ lombok
+ 1.18.20
+ provided
+
+
-
+
+ ${project.artifactId}
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
-
- org.scala-tools
- maven-scala-plugin
- 2.15.2
-
-
- scala-compile-first
-
- compile
-
-
-
- **/*.scala
-
-
-
-
-
+
+
-
- org.codehaus.mojo
- build-helper-maven-plugin
- 3.2.0
-
-
- add-source
- generate-sources
-
- add-source
-
-
-
- src/main/java
- src/main/scala
-
-
-
-
-
+
+
+ dev
+
+ true
+
+
-
- maven-compiler-plugin
-
- ${compiler.version}
- ${compiler.version}
- ${project.build.sourceEncoding}
-
-
-
- com.github.eirslett
- frontend-maven-plugin
- ${frontend-maven-plugin.version}
-
- ${ui.path}
- v8.17.0
- http://npm.taobao.org/mirrors/node/
-
-
-
-
-
-
-
-
-
- npm install
-
- npm
-
-
- install --registry=https://registry.npmjs.org/
-
-
-
- npm run build
-
- npm
-
-
- run build
-
-
-
-
-
- maven-resources-plugin
- 3.1.0
-
- ${project.build.sourceEncoding}
- ${project.build.directory}
-
-
- ${basedir}/target/classes/public
- ${ui.path}/dist
-
-
- ${basedir}/target/classes
- src/main/resources
-
-
-
-
-
-
+
+ deploy
+
+
+
+
+ org.scala-tools
+ maven-scala-plugin
+ 2.15.2
+
+
+ scala-compile-first
+
+ compile
+
+
+
+ **/*.scala
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 3.2.0
+
+
+ add-source
+ generate-sources
+
+ add-source
+
+
+
+ src/main/java
+ src/main/scala
+
+
+
+
+
+
+
+ maven-compiler-plugin
+
+ ${compiler.version}
+ ${compiler.version}
+ ${project.build.sourceEncoding}
+
+
+
+ com.github.eirslett
+ frontend-maven-plugin
+ ${frontend-maven-plugin.version}
+
+ ${ui.path}
+ v8.17.0
+ http://npm.taobao.org/mirrors/node/
+
+
+
+
+
+
+
+
+
+ npm install
+
+ npm
+
+
+ install --registry=https://registry.npmjs.org/
+
+
+
+ npm run build
+
+ npm
+
+
+ run build
+
+
+
+
+
+ maven-resources-plugin
+ 3.1.0
+
+ ${project.build.sourceEncoding}
+ ${project.build.directory}
+
+
+ ${basedir}/target/classes/public
+ ${ui.path}/dist
+
+
+ ${basedir}/target/classes
+ src/main/resources
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/xuxd/kafka/console/beans/AclEntry.java b/src/main/java/com/xuxd/kafka/console/beans/AclEntry.java
index 4f8ef77..3d392d0 100644
--- a/src/main/java/com/xuxd/kafka/console/beans/AclEntry.java
+++ b/src/main/java/com/xuxd/kafka/console/beans/AclEntry.java
@@ -1,7 +1,6 @@
package com.xuxd.kafka.console.beans;
import java.util.Objects;
-import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.kafka.common.acl.AccessControlEntry;
import org.apache.kafka.common.acl.AccessControlEntryFilter;
@@ -21,7 +20,6 @@ import org.apache.kafka.common.security.auth.KafkaPrincipal;
* @author xuxd
* @date 2021-08-28 20:17:27
**/
-@Data
public class AclEntry {
private String resourceType;
@@ -100,4 +98,72 @@ public class AclEntry {
entry.setPermissionType(this.permissionType);
return entry;
}
+
+ public String getResourceType() {
+ return resourceType;
+ }
+
+ public void setResourceType(String resourceType) {
+ this.resourceType = resourceType;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getPatternType() {
+ return patternType;
+ }
+
+ public void setPatternType(String patternType) {
+ this.patternType = patternType;
+ }
+
+ public String getPrincipal() {
+ return principal;
+ }
+
+ public void setPrincipal(String principal) {
+ this.principal = principal;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public String getOperation() {
+ return operation;
+ }
+
+ public void setOperation(String operation) {
+ this.operation = operation;
+ }
+
+ public String getPermissionType() {
+ return permissionType;
+ }
+
+ public void setPermissionType(String permissionType) {
+ this.permissionType = permissionType;
+ }
+
+ @Override public String toString() {
+ return "AclEntry{" +
+ "resourceType='" + resourceType + '\'' +
+ ", name='" + name + '\'' +
+ ", patternType='" + patternType + '\'' +
+ ", principal='" + principal + '\'' +
+ ", host='" + host + '\'' +
+ ", operation='" + operation + '\'' +
+ ", permissionType='" + permissionType + '\'' +
+ '}';
+ }
}
diff --git a/src/main/java/com/xuxd/kafka/console/service/impl/AclServiceImpl.java b/src/main/java/com/xuxd/kafka/console/service/impl/AclServiceImpl.java
index 83d6cb5..c6ebd80 100644
--- a/src/main/java/com/xuxd/kafka/console/service/impl/AclServiceImpl.java
+++ b/src/main/java/com/xuxd/kafka/console/service/impl/AclServiceImpl.java
@@ -6,6 +6,7 @@ import com.xuxd.kafka.console.beans.CounterMap;
import com.xuxd.kafka.console.beans.ResponseData;
import com.xuxd.kafka.console.service.AclService;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -13,6 +14,7 @@ import java.util.stream.Collectors;
import kafka.console.KafkaAclConsole;
import kafka.console.KafkaConfigConsole;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
import org.apache.kafka.common.acl.AclBinding;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -35,7 +37,7 @@ public class AclServiceImpl implements AclService {
@Override public ResponseData> getUserList() {
try {
- return ResponseData.create(Set.class).data(configConsole.getUserList()).success();
+ return ResponseData.create(Set.class).data(configConsole.getUserList(null)).success();
} catch (Exception e) {
log.error("getUserList error.", e);
return ResponseData.create().failed();
@@ -60,8 +62,21 @@ public class AclServiceImpl implements AclService {
List aclBindingList = entry.isNull() ? aclConsole.getAclList(null) : aclConsole.getAclList(entry);
List entryList = aclBindingList.stream().map(x -> AclEntry.valueOf(x)).collect(Collectors.toList());
Map> entryMap = entryList.stream().collect(Collectors.groupingBy(AclEntry::getPrincipal));
+ Map>> resultMap = new HashMap<>();
+ entryMap.forEach((k, v) -> {
+ Map> map = v.stream().collect(Collectors.groupingBy(e -> e.getResourceType() + "#" + e.getName()));
+ resultMap.put(k, map);
+ });
+ if (entry.isNull() || StringUtils.isNotBlank(entry.getPrincipal())) {
+ Set userList = configConsole.getUserList(StringUtils.isNotBlank(entry.getPrincipal()) ? Collections.singletonList(entry.getPrincipal()) : null);
+ userList.forEach(u -> {
+ if (!resultMap.containsKey(u)) {
+ resultMap.put(u, Collections.emptyMap());
+ }
+ });
+ }
- return ResponseData.create().data(new CounterMap<>(entryMap)).success();
+ return ResponseData.create().data(new CounterMap<>(resultMap)).success();
}
@Override public ResponseData deleteAcl(AclEntry entry) {
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 03b586e..834e2f3 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -1,5 +1,7 @@
server:
port: 7766
+ servlet:
+ context-path: /kafka-console
kafka:
config:
diff --git a/src/main/scala/kafka/console/KafkaAclConsole.scala b/src/main/scala/kafka/console/KafkaAclConsole.scala
index 8e7c0f1..590edf4 100644
--- a/src/main/scala/kafka/console/KafkaAclConsole.scala
+++ b/src/main/scala/kafka/console/KafkaAclConsole.scala
@@ -41,7 +41,7 @@ class KafkaAclConsole(config: KafkaConfig) extends KafkaConsole(config: KafkaCon
}
var principal: String = null
- if ( StringUtils.isNotBlank(entry.getPrincipal) && !KafkaPrincipal.ANONYMOUS.toString.equalsIgnoreCase(f.entryFilter().principal())) {
+ if (StringUtils.isNotBlank(entry.getPrincipal()) && !KafkaPrincipal.ANONYMOUS.toString.equalsIgnoreCase(f.entryFilter().principal())) {
principal = f.entryFilter().principal();
}
val filter = new AclBindingFilter(new ResourcePatternFilter(resourceType, name, f.patternFilter().patternType()),
diff --git a/src/main/scala/kafka/console/KafkaConfigConsole.scala b/src/main/scala/kafka/console/KafkaConfigConsole.scala
index efe3ce9..6c4c8c1 100644
--- a/src/main/scala/kafka/console/KafkaConfigConsole.scala
+++ b/src/main/scala/kafka/console/KafkaConfigConsole.scala
@@ -17,9 +17,9 @@ class KafkaConfigConsole(config: KafkaConfig) extends KafkaConsole(config: Kafka
private val defaultIterations = 4096
- def getUserList(): Set[String] = {
+ def getUserList(users: util.List[String]): Set[String] = {
withAdminClient({
- adminClient => adminClient.describeUserScramCredentials().all().get().keySet()
+ adminClient => adminClient.describeUserScramCredentials(users).all().get().keySet()
}).asInstanceOf[Set[String]]
}
diff --git a/ui/package-lock.json b/ui/package-lock.json
index d1484a7..b9632f2 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -2587,6 +2587,14 @@
"integrity": "sha1-1h9G2DslGSUOJ4Ta9bCUeai0HFk=",
"dev": true
},
+ "axios": {
+ "version": "0.21.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
+ "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
+ "requires": {
+ "follow-redirects": "^1.10.0"
+ }
+ },
"babel-eslint": {
"version": "10.1.0",
"resolved": "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.1.0.tgz",
@@ -5826,8 +5834,7 @@
"follow-redirects": {
"version": "1.14.2",
"resolved": "https://registry.nlark.com/follow-redirects/download/follow-redirects-1.14.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.14.2.tgz",
- "integrity": "sha1-zsuCUEfAD15msUL5D+1PUV3seJs=",
- "dev": true
+ "integrity": "sha1-zsuCUEfAD15msUL5D+1PUV3seJs="
},
"for-in": {
"version": "1.0.2",
diff --git a/ui/package.json b/ui/package.json
index f46bbca..5408661 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -9,6 +9,7 @@
},
"dependencies": {
"ant-design-vue": "^1.7.8",
+ "axios": "^0.21.1",
"core-js": "^3.6.5",
"moment": "^2.29.1",
"vue": "^2.6.11",
diff --git a/ui/src/main.js b/ui/src/main.js
index e85752c..3f9f7ef 100644
--- a/ui/src/main.js
+++ b/ui/src/main.js
@@ -5,9 +5,11 @@ import store from "./store";
// eslint-disable-next-line no-unused-vars
import Antd from "ant-design-vue";
import "ant-design-vue/dist/antd.css";
+import { VueAxios } from "./utils/request";
Vue.config.productionTip = false;
Vue.use(Antd);
+Vue.use(VueAxios);
new Vue({
router,
diff --git a/ui/src/utils/axios.js b/ui/src/utils/axios.js
new file mode 100644
index 0000000..c28a7ae
--- /dev/null
+++ b/ui/src/utils/axios.js
@@ -0,0 +1,33 @@
+const VueAxios = {
+ vm: {},
+ // eslint-disable-next-line no-unused-vars
+ install(Vue, instance) {
+ if (this.installed) {
+ return;
+ }
+ this.installed = true;
+
+ if (!instance) {
+ // eslint-disable-next-line no-console
+ console.error("You have to install axios");
+ return;
+ }
+
+ Vue.axios = instance;
+
+ Object.defineProperties(Vue.prototype, {
+ axios: {
+ get: function get() {
+ return instance;
+ },
+ },
+ $http: {
+ get: function get() {
+ return instance;
+ },
+ },
+ });
+ },
+};
+
+export { VueAxios };
diff --git a/ui/src/utils/request.js b/ui/src/utils/request.js
new file mode 100644
index 0000000..67136df
--- /dev/null
+++ b/ui/src/utils/request.js
@@ -0,0 +1,44 @@
+import axios from "axios";
+import notification from "ant-design-vue/es/notification";
+import { VueAxios } from "./axios";
+
+// 创建 axios 实例
+const request = axios.create({
+ // API 请求的默认前缀
+ baseURL: "/kafka-console",
+ timeout: 10000, // 请求超时时间
+});
+
+// 异常拦截处理器
+const errorHandler = (error) => {
+ if (error.response) {
+ const data = error.response.data;
+ notification.error({
+ message: error.response.status,
+ description: JSON.stringify(data),
+ });
+ }
+ return Promise.reject(error);
+};
+
+// request interceptor
+// request.interceptors.request.use(config => {
+//
+// return config
+// }, errorHandler)
+
+// response interceptor
+request.interceptors.response.use((response) => {
+ return response.data;
+}, errorHandler);
+
+const installer = {
+ vm: {},
+ install(Vue) {
+ Vue.use(VueAxios, request);
+ },
+};
+
+export default request;
+
+export { installer as VueAxios, request as axios };
diff --git a/ui/src/views/acl/Acl.vue b/ui/src/views/acl/Acl.vue
index 660d76f..f87e911 100644
--- a/ui/src/views/acl/Acl.vue
+++ b/ui/src/views/acl/Acl.vue
@@ -1,6 +1,50 @@