diff --git a/src/main/java/com/xuxd/kafka/console/service/AclService.java b/src/main/java/com/xuxd/kafka/console/service/AclService.java index 2851d30..3949724 100644 --- a/src/main/java/com/xuxd/kafka/console/service/AclService.java +++ b/src/main/java/com/xuxd/kafka/console/service/AclService.java @@ -40,4 +40,6 @@ public interface AclService { ResponseData getOperationList(); + ResponseData getUserDetail(String username); + } 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 30da112..6b29319 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 @@ -181,6 +181,18 @@ public class AclServiceImpl implements AclService, SmartInitializingSingleton { return ResponseData.create().data(operations).success(); } + @Override public ResponseData getUserDetail(String username) { + Map param = new HashMap<>(); + param.put("username", username); + List dos = kafkaUserMapper.selectByMap(param); + if (dos.isEmpty()) { + return ResponseData.create().data(new CounterList<>(dos)).success("Retrieved the user info is null."); + } + // check for consistency. + + return null; + } + @Override public void afterSingletonsInstantiated() { if (kafkaConfig.isAdminCreate()) { log.info("Start create admin user, username: {}, password: {}", kafkaConfig.getAdminUsername(), kafkaConfig.getAdminPassword()); diff --git a/src/main/scala/kafka/console/KafkaConfigConsole.scala b/src/main/scala/kafka/console/KafkaConfigConsole.scala index 1e92126..9dfeaeb 100644 --- a/src/main/scala/kafka/console/KafkaConfigConsole.scala +++ b/src/main/scala/kafka/console/KafkaConfigConsole.scala @@ -7,10 +7,8 @@ import java.util.{Properties, Set} import com.xuxd.kafka.console.config.KafkaConfig import kafka.server.ConfigType import kafka.utils.Implicits.PropertiesOps -import kafka.zk.{AdminZkClient, KafkaZkClient} import org.apache.kafka.clients.admin._ import org.apache.kafka.common.security.scram.internals.{ScramCredentialUtils, ScramFormatter} -import org.apache.kafka.common.utils.Time /** * kafka-console-ui. @@ -51,27 +49,24 @@ class KafkaConfigConsole(config: KafkaConfig) extends KafkaConsole(config: Kafka } def addOrUpdateUserWithZK(name: String, pass: String): Boolean = { + withZKClient(adminZkClient => { + try { + val credential = new ScramFormatter(org.apache.kafka.common.security.scram.internals.ScramMechanism.forMechanismName(config.getSaslMechanism)) + .generateCredential(pass, defaultIterations) + val credentialStr = ScramCredentialUtils.credentialToString(credential) - val zkClient = KafkaZkClient(config.getZookeeperAddr, false, 30000, 30000, Int.MaxValue, Time.SYSTEM) - val adminZkClient = new AdminZkClient(zkClient) - try { - val credential = new ScramFormatter(org.apache.kafka.common.security.scram.internals.ScramMechanism.forMechanismName(config.getSaslMechanism)) - .generateCredential(pass, defaultIterations) - val credentialStr = ScramCredentialUtils.credentialToString(credential) + val userConfig: Properties = new Properties() + userConfig.put(config.getSaslMechanism, credentialStr) - val userConfig: Properties = new Properties() - userConfig.put(config.getSaslMechanism, credentialStr) - - val configs = adminZkClient.fetchEntityConfig(ConfigType.User, name) - userConfig ++= configs - adminZkClient.changeConfigs(ConfigType.User, name, userConfig) - true - } catch { - case e: Exception => log.error("addOrUpdateAdminWithZK error.", e) - false - } finally { - zkClient.close() - } + val configs = adminZkClient.fetchEntityConfig(ConfigType.User, name) + userConfig ++= configs + adminZkClient.changeConfigs(ConfigType.User, name, userConfig) + true + } catch { + case e: Exception => log.error("addOrUpdateAdminWithZK error.", e) + false + } + }).asInstanceOf[Boolean] } def deleteUser(name: String): (Boolean, String) = { diff --git a/src/main/scala/kafka/console/KafkaConsole.scala b/src/main/scala/kafka/console/KafkaConsole.scala index 78ab1a3..9ad1949 100644 --- a/src/main/scala/kafka/console/KafkaConsole.scala +++ b/src/main/scala/kafka/console/KafkaConsole.scala @@ -3,9 +3,11 @@ package kafka.console import java.util.Properties import com.xuxd.kafka.console.config.KafkaConfig +import kafka.zk.{AdminZkClient, KafkaZkClient} import org.apache.kafka.clients.CommonClientConfigs import org.apache.kafka.clients.admin.{Admin, AdminClientConfig} import org.apache.kafka.common.config.SaslConfigs +import org.apache.kafka.common.utils.Time /** * kafka-console-ui. @@ -25,6 +27,16 @@ class KafkaConsole(config: KafkaConfig) { } } + protected def withZKClient(f: AdminZkClient => Any): Any = { + val zkClient = KafkaZkClient(config.getZookeeperAddr, false, 30000, 30000, Int.MaxValue, Time.SYSTEM) + val adminZkClient = new AdminZkClient(zkClient) + try { + f(adminZkClient) + } finally { + zkClient.close() + } + } + private def createAdminClient(): Admin = { val props: Properties = new Properties(); props.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, config.getBootstrapServer) diff --git a/ui/src/views/acl/Acl.vue b/ui/src/views/acl/Acl.vue index cff64ec..99db37f 100644 --- a/ui/src/views/acl/Acl.vue +++ b/ui/src/views/acl/Acl.vue @@ -53,7 +53,23 @@ > - +
+ {{ username }}详情 + +
+ +
- +
- +
{{ t }}
- +
- - 删除 + 删除 - - + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - + +
@@ -164,6 +161,7 @@ import ManageProducerAuth from "@/views/acl/ManageProducerAuth"; import ManageConsumerAuth from "@/views/acl/ManageConsumerAuth"; import AddAuth from "@/views/acl/AddAuth"; import AclDetail from "@/views/acl/AclDetail"; +import UserDetail from "@/views/acl/UserDetail"; export default { name: "Acl", @@ -173,14 +171,13 @@ export default { ManageConsumerAuth, AddAuth, AclDetail, + UserDetail, }, data() { return { queryParam: {}, data: [], columns, - innerColumns, - innerData, selectRow: {}, form: this.$form.createForm(this, { name: "advanced_search" }), showUpdateUser: false, @@ -189,6 +186,7 @@ export default { openManageConsumerAuthDialog: false, openAddAuthDialog: false, openAclDetailDialog: false, + openUserDetailDialog: false, selectDetail: { resourceName: "", resourceType: "", @@ -273,6 +271,10 @@ export default { this.selectDetail.username = username; this.openAclDetailDialog = true; }, + onUserDetail(username) { + this.selectDetail.username = username; + this.openUserDetailDialog = true; + }, closeManageProducerAuthDialog() { this.openManageProducerAuthDialog = false; getAclList(this.data, this.queryParam); @@ -289,6 +291,9 @@ export default { this.openAclDetailDialog = false; getAclList(this.data, this.queryParam); }, + closeUserDetailDialog() { + this.openUserDetailDialog = false; + }, }, created() { getAclList(this.data, this.queryParam); @@ -329,7 +334,14 @@ function getAclList(data, requestParameters) { } const columns = [ - { title: "用户名", dataIndex: "username", key: "username", width: 200 }, + { + title: "用户名", + dataIndex: "username", + key: "username", + width: 300, + slots: { title: "username" }, + scopedSlots: { customRender: "username" }, + }, { title: "topic列表", dataIndex: "topicList", @@ -348,32 +360,9 @@ const columns = [ title: "操作", key: "operation", scopedSlots: { customRender: "operation" }, - width: 350, + width: 500, }, ]; - -const innerColumns = [ - { title: "Date", dataIndex: "date", key: "date" }, - { title: "Name", dataIndex: "name", key: "name" }, - { title: "Status", key: "state", scopedSlots: { customRender: "status" } }, - { title: "Upgrade Status", dataIndex: "upgradeNum", key: "upgradeNum" }, - { - title: "Action", - dataIndex: "operation", - key: "operation", - scopedSlots: { customRender: "operation" }, - }, -]; - -const innerData = []; -for (let i = 0; i < 3; ++i) { - innerData.push({ - key: i, - date: "2014-12-24 23:12:00", - name: "This is production name", - upgradeNum: "Upgraded: 56", - }); -} diff --git a/ui/src/views/acl/UserDetail.vue b/ui/src/views/acl/UserDetail.vue new file mode 100644 index 0000000..4b6e9f7 --- /dev/null +++ b/ui/src/views/acl/UserDetail.vue @@ -0,0 +1,51 @@ + + + + +