From fce1154c36367a76aa073850533e33a0c3ac7709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=99=93=E4=B8=9C?= <763795151@qq.com> Date: Tue, 11 Apr 2023 22:01:16 +0800 Subject: [PATCH 01/13] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=AE=A1=E7=90=86=EF=BC=9A=E7=94=A8=E6=88=B7=E3=80=81=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E3=80=81=E6=9D=83=E9=99=90=E6=96=B0=E5=A2=9E=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 + .../console/KafkaConsoleUiApplication.java | 3 + .../console/aspect/ControllerLogAspect.java | 117 ++++++++++++++++++ .../aspect/annotation/ControllerLog.java | 15 +++ .../console/beans/dos/SysPermissionDO.java | 29 +++++ .../kafka/console/beans/dos/SysRoleDO.java | 24 ++++ .../kafka/console/beans/dos/SysUserDO.java | 26 ++++ .../console/beans/dto/SysPermissionDTO.java | 32 +++++ .../kafka/console/beans/dto/SysRoleDTO.java | 26 ++++ .../kafka/console/beans/dto/SysUserDTO.java | 29 +++++ .../controller/UserManageController.java | 44 +++++++ .../console/dao/SysPermissionMapper.java | 13 ++ .../xuxd/kafka/console/dao/SysRoleMapper.java | 11 ++ .../xuxd/kafka/console/dao/SysUserMapper.java | 11 ++ .../console/service/UserManageService.java | 24 ++++ .../service/impl/UserManageServiceImpl.java | 54 ++++++++ src/main/resources/db/schema-h2.sql | 31 +++++ ui/src/App.vue | 2 + ui/src/router/index.js | 6 + ui/src/views/user/UserManage.vue | 35 ++++++ 20 files changed, 537 insertions(+) create mode 100644 src/main/java/com/xuxd/kafka/console/aspect/ControllerLogAspect.java create mode 100644 src/main/java/com/xuxd/kafka/console/aspect/annotation/ControllerLog.java create mode 100644 src/main/java/com/xuxd/kafka/console/beans/dos/SysPermissionDO.java create mode 100644 src/main/java/com/xuxd/kafka/console/beans/dos/SysRoleDO.java create mode 100644 src/main/java/com/xuxd/kafka/console/beans/dos/SysUserDO.java create mode 100644 src/main/java/com/xuxd/kafka/console/beans/dto/SysPermissionDTO.java create mode 100644 src/main/java/com/xuxd/kafka/console/beans/dto/SysRoleDTO.java create mode 100644 src/main/java/com/xuxd/kafka/console/beans/dto/SysUserDTO.java create mode 100644 src/main/java/com/xuxd/kafka/console/controller/UserManageController.java create mode 100644 src/main/java/com/xuxd/kafka/console/dao/SysPermissionMapper.java create mode 100644 src/main/java/com/xuxd/kafka/console/dao/SysRoleMapper.java create mode 100644 src/main/java/com/xuxd/kafka/console/dao/SysUserMapper.java create mode 100644 src/main/java/com/xuxd/kafka/console/service/UserManageService.java create mode 100644 src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java create mode 100644 ui/src/views/user/UserManage.vue diff --git a/pom.xml b/pom.xml index 3e6d540..5755458 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,11 @@ spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-aop + + org.springframework.boot spring-boot-starter-test diff --git a/src/main/java/com/xuxd/kafka/console/KafkaConsoleUiApplication.java b/src/main/java/com/xuxd/kafka/console/KafkaConsoleUiApplication.java index aa36b29..73d9a44 100644 --- a/src/main/java/com/xuxd/kafka/console/KafkaConsoleUiApplication.java +++ b/src/main/java/com/xuxd/kafka/console/KafkaConsoleUiApplication.java @@ -6,6 +6,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.scheduling.annotation.EnableScheduling; +/** + * @author 晓东哥哥 + */ @MapperScan("com.xuxd.kafka.console.dao") @SpringBootApplication @EnableScheduling diff --git a/src/main/java/com/xuxd/kafka/console/aspect/ControllerLogAspect.java b/src/main/java/com/xuxd/kafka/console/aspect/ControllerLogAspect.java new file mode 100644 index 0000000..139fbf8 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/aspect/ControllerLogAspect.java @@ -0,0 +1,117 @@ +package com.xuxd.kafka.console.aspect; + +import com.xuxd.kafka.console.aspect.annotation.ControllerLog; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +/** + * @author 晓东哥哥 + */ +@Slf4j +@Order(-1) +@Aspect +@Component +public class ControllerLogAspect { + + private Map descMap = new HashMap<>(); + + private ReentrantLock lock = new ReentrantLock(); + + @Pointcut("@annotation(com.xuxd.kafka.console.aspect.annotation.ControllerLog)") + private void pointcut() { + + } + + @Around("pointcut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + StringBuilder params = new StringBuilder("["); + try { + String methodName = getMethodFullName(joinPoint.getTarget().getClass().getName(), joinPoint.getSignature().getName()); + + if (!descMap.containsKey(methodName)) { + cacheDescInfo(joinPoint); + } + + Object[] args = joinPoint.getArgs(); + long startTime = System.currentTimeMillis(); + Object res = joinPoint.proceed(); + long endTime = System.currentTimeMillis(); + + for (int i = 0; i < args.length; i++) { + params.append(args[i]); + } + params.append("]"); + + String resStr = "[" + (res != null ? res.toString() : "") + "]"; + + StringBuilder sb = new StringBuilder(); + String shortMethodName = descMap.getOrDefault(methodName, ".-"); + shortMethodName = shortMethodName.substring(shortMethodName.lastIndexOf(".") + 1); + sb.append("[").append(shortMethodName) + .append("调用完成: ") + .append("请求参数=").append(params).append(", ") + .append("响应值=").append(resStr).append(", ") + .append("耗时=").append(endTime - startTime) + .append(" ms"); + log.info(sb.toString()); + return res; + } catch (Throwable e) { + log.error("调用方法异常, 请求参数:" + params, e); + throw e; + } + } + + private void cacheDescInfo(ProceedingJoinPoint joinPoint) { + lock.lock(); + try { + String methodName = joinPoint.getSignature().getName(); + Class aClass = joinPoint.getTarget().getClass(); + + Method method = null; + try { + Object[] args = joinPoint.getArgs(); + + Class[] clzArr = new Class[args.length]; + for (int i = 0; i < args.length; i++) { + clzArr[i] = args[i].getClass(); + } + method = aClass.getDeclaredMethod(methodName, clzArr); + + } catch (Exception e) { + log.warn("cacheDescInfo error: {}", e.getMessage()); + } + + String fullMethodName = getMethodFullName(aClass.getName(), methodName); + String desc = "[" + fullMethodName + "]"; + if (method == null) { + descMap.put(fullMethodName, desc); + return; + } + + ControllerLog controllerLog = method.getAnnotation(ControllerLog.class); + String value = controllerLog.value(); + if (StringUtils.isBlank(value)) { + descMap.put(fullMethodName, desc); + } else { + descMap.put(fullMethodName, value); + } + } finally { + lock.unlock(); + } + } + + private String getMethodFullName(String className, String methodName) { + return className + "#" + methodName; + } +} diff --git a/src/main/java/com/xuxd/kafka/console/aspect/annotation/ControllerLog.java b/src/main/java/com/xuxd/kafka/console/aspect/annotation/ControllerLog.java new file mode 100644 index 0000000..b74a2bb --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/aspect/annotation/ControllerLog.java @@ -0,0 +1,15 @@ +package com.xuxd.kafka.console.aspect.annotation; + +import java.lang.annotation.*; + +/** + * 该注解用到controller层的方法上 + * @author 晓东哥哥 + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface ControllerLog { + + String value() default ""; +} diff --git a/src/main/java/com/xuxd/kafka/console/beans/dos/SysPermissionDO.java b/src/main/java/com/xuxd/kafka/console/beans/dos/SysPermissionDO.java new file mode 100644 index 0000000..2548878 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/beans/dos/SysPermissionDO.java @@ -0,0 +1,29 @@ +package com.xuxd.kafka.console.beans.dos; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @author: xuxd + * @date: 2023/4/11 21:17 + **/ +@Data +@TableName("t_sys_permission") +public class SysPermissionDO { + + @TableId(type = IdType.AUTO) + private Long id; + + private String name; + + /** + * 权限类型: 0:菜单,1:按钮 + */ + private Integer type; + + private Long parentId; + + private String permission; +} diff --git a/src/main/java/com/xuxd/kafka/console/beans/dos/SysRoleDO.java b/src/main/java/com/xuxd/kafka/console/beans/dos/SysRoleDO.java new file mode 100644 index 0000000..fc6f65a --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/beans/dos/SysRoleDO.java @@ -0,0 +1,24 @@ +package com.xuxd.kafka.console.beans.dos; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @author: xuxd + * @date: 2023/4/11 21:17 + **/ +@Data +@TableName("t_sys_role") +public class SysRoleDO { + + @TableId(type = IdType.AUTO) + private Long id; + + private String roleName; + + private String description; + + private String permissionIds; +} diff --git a/src/main/java/com/xuxd/kafka/console/beans/dos/SysUserDO.java b/src/main/java/com/xuxd/kafka/console/beans/dos/SysUserDO.java new file mode 100644 index 0000000..df70186 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/beans/dos/SysUserDO.java @@ -0,0 +1,26 @@ +package com.xuxd.kafka.console.beans.dos; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @author: xuxd + * @date: 2023/4/11 21:17 + **/ +@Data +@TableName("t_sys_user") +public class SysUserDO { + + @TableId(type = IdType.AUTO) + private Long id; + + private String username; + + private String password; + + private String salt; + + private String roleIds; +} diff --git a/src/main/java/com/xuxd/kafka/console/beans/dto/SysPermissionDTO.java b/src/main/java/com/xuxd/kafka/console/beans/dto/SysPermissionDTO.java new file mode 100644 index 0000000..5f34954 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/beans/dto/SysPermissionDTO.java @@ -0,0 +1,32 @@ +package com.xuxd.kafka.console.beans.dto; + +import com.xuxd.kafka.console.beans.dos.SysPermissionDO; +import lombok.Data; + +/** + * @author: xuxd + * @date: 2023/4/11 21:17 + **/ +@Data +public class SysPermissionDTO { + + private String name; + + /** + * 权限类型: 0:菜单,1:按钮 + */ + private Integer type; + + private Long parentId; + + private String permission; + + public SysPermissionDO toSysPermissionDO() { + SysPermissionDO permissionDO = new SysPermissionDO(); + permissionDO.setName(this.name); + permissionDO.setType(this.type); + permissionDO.setParentId(this.parentId); + permissionDO.setPermission(this.permission); + return permissionDO; + } +} diff --git a/src/main/java/com/xuxd/kafka/console/beans/dto/SysRoleDTO.java b/src/main/java/com/xuxd/kafka/console/beans/dto/SysRoleDTO.java new file mode 100644 index 0000000..9ee1fc6 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/beans/dto/SysRoleDTO.java @@ -0,0 +1,26 @@ +package com.xuxd.kafka.console.beans.dto; + +import com.xuxd.kafka.console.beans.dos.SysRoleDO; +import lombok.Data; + +/** + * @author: xuxd + * @date: 2023/4/11 21:17 + **/ +@Data +public class SysRoleDTO { + + private String roleName; + + private String description; + + private String permissionIds; + + public SysRoleDO toDO() { + SysRoleDO roleDO = new SysRoleDO(); + roleDO.setRoleName(this.roleName); + roleDO.setDescription(this.description); + roleDO.setPermissionIds(this.permissionIds); + return roleDO; + } +} diff --git a/src/main/java/com/xuxd/kafka/console/beans/dto/SysUserDTO.java b/src/main/java/com/xuxd/kafka/console/beans/dto/SysUserDTO.java new file mode 100644 index 0000000..2c8be8e --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/beans/dto/SysUserDTO.java @@ -0,0 +1,29 @@ +package com.xuxd.kafka.console.beans.dto; + +import com.xuxd.kafka.console.beans.dos.SysUserDO; +import lombok.Data; + +/** + * @author: xuxd + * @date: 2023/4/11 21:17 + **/ +@Data +public class SysUserDTO { + + private String username; + + private String password; + + private String salt; + + private String roleIds; + + public SysUserDO toDO() { + SysUserDO userDO = new SysUserDO(); + userDO.setUsername(this.username); + userDO.setPassword(this.password); + userDO.setSalt(this.salt); + userDO.setRoleIds(this.roleIds); + return userDO; + } +} diff --git a/src/main/java/com/xuxd/kafka/console/controller/UserManageController.java b/src/main/java/com/xuxd/kafka/console/controller/UserManageController.java new file mode 100644 index 0000000..f10074d --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/controller/UserManageController.java @@ -0,0 +1,44 @@ +package com.xuxd.kafka.console.controller; + +import com.xuxd.kafka.console.aspect.annotation.ControllerLog; +import com.xuxd.kafka.console.beans.dto.SysPermissionDTO; +import com.xuxd.kafka.console.beans.dto.SysRoleDTO; +import com.xuxd.kafka.console.beans.dto.SysUserDTO; +import com.xuxd.kafka.console.service.UserManageService; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author: xuxd + * @date: 2023/4/11 21:34 + **/ +@RestController +@RequestMapping("/sys/user/manage") +public class UserManageController { + + private final UserManageService userManageService; + + public UserManageController(UserManageService userManageService) { + this.userManageService = userManageService; + } + + @ControllerLog("新增用户") + @PostMapping("/user") + public Object addUser(@RequestBody SysUserDTO userDTO) { + return userManageService.addUser(userDTO); + } + + @ControllerLog("新增角色") + @PostMapping("/role") + public Object addRole(@RequestBody SysRoleDTO roleDTO) { + return userManageService.addRole(roleDTO); + } + + @ControllerLog("新增权限") + @PostMapping("/permission") + public Object addPermission(@RequestBody SysPermissionDTO permissionDTO) { + return userManageService.addPermission(permissionDTO); + } +} diff --git a/src/main/java/com/xuxd/kafka/console/dao/SysPermissionMapper.java b/src/main/java/com/xuxd/kafka/console/dao/SysPermissionMapper.java new file mode 100644 index 0000000..f88ff78 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/dao/SysPermissionMapper.java @@ -0,0 +1,13 @@ +package com.xuxd.kafka.console.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xuxd.kafka.console.beans.dos.SysPermissionDO; + +/** + * 系统权限 . + * + * @author: xuxd + * @date: 2023/4/11 21:21 + **/ +public interface SysPermissionMapper extends BaseMapper { +} diff --git a/src/main/java/com/xuxd/kafka/console/dao/SysRoleMapper.java b/src/main/java/com/xuxd/kafka/console/dao/SysRoleMapper.java new file mode 100644 index 0000000..d70ad4b --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/dao/SysRoleMapper.java @@ -0,0 +1,11 @@ +package com.xuxd.kafka.console.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xuxd.kafka.console.beans.dos.SysRoleDO; + +/** + * @author: xuxd + * @date: 2023/4/11 21:22 + **/ +public interface SysRoleMapper extends BaseMapper { +} diff --git a/src/main/java/com/xuxd/kafka/console/dao/SysUserMapper.java b/src/main/java/com/xuxd/kafka/console/dao/SysUserMapper.java new file mode 100644 index 0000000..7a3af87 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/dao/SysUserMapper.java @@ -0,0 +1,11 @@ +package com.xuxd.kafka.console.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xuxd.kafka.console.beans.dos.SysUserDO; + +/** + * @author: xuxd + * @date: 2023/4/11 21:22 + **/ +public interface SysUserMapper extends BaseMapper { +} diff --git a/src/main/java/com/xuxd/kafka/console/service/UserManageService.java b/src/main/java/com/xuxd/kafka/console/service/UserManageService.java new file mode 100644 index 0000000..a6677e5 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/service/UserManageService.java @@ -0,0 +1,24 @@ +package com.xuxd.kafka.console.service; + +import com.xuxd.kafka.console.beans.ResponseData; +import com.xuxd.kafka.console.beans.dto.SysPermissionDTO; +import com.xuxd.kafka.console.beans.dto.SysRoleDTO; +import com.xuxd.kafka.console.beans.dto.SysUserDTO; + +/** + * 登录用户权限管理. + * + * @author: xuxd + * @date: 2023/4/11 21:24 + **/ +public interface UserManageService { + + /** + * 增加权限 + */ + ResponseData addPermission(SysPermissionDTO permissionDTO); + + ResponseData addRole(SysRoleDTO roleDTO); + + ResponseData addUser(SysUserDTO userDTO); +} diff --git a/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java b/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java new file mode 100644 index 0000000..dc85b96 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java @@ -0,0 +1,54 @@ +package com.xuxd.kafka.console.service.impl; + +import com.xuxd.kafka.console.beans.ResponseData; +import com.xuxd.kafka.console.beans.dto.SysPermissionDTO; +import com.xuxd.kafka.console.beans.dto.SysRoleDTO; +import com.xuxd.kafka.console.beans.dto.SysUserDTO; +import com.xuxd.kafka.console.dao.SysPermissionMapper; +import com.xuxd.kafka.console.dao.SysRoleMapper; +import com.xuxd.kafka.console.dao.SysUserMapper; +import com.xuxd.kafka.console.service.UserManageService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.stereotype.Service; + +/** + * @author: xuxd + * @date: 2023/4/11 21:24 + **/ +@Slf4j +@Service +public class UserManageServiceImpl implements UserManageService { + + private final SysUserMapper userMapper; + + private final SysRoleMapper roleMapper; + + private final SysPermissionMapper permissionMapper; + + public UserManageServiceImpl(ObjectProvider userMapper, + ObjectProvider roleMapper, + ObjectProvider permissionMapper) { + this.userMapper = userMapper.getIfAvailable(); + this.roleMapper = roleMapper.getIfAvailable(); + this.permissionMapper = permissionMapper.getIfAvailable(); + } + + @Override + public ResponseData addPermission(SysPermissionDTO permissionDTO) { + permissionMapper.insert(permissionDTO.toSysPermissionDO()); + return ResponseData.create().success(); + } + + @Override + public ResponseData addRole(SysRoleDTO roleDTO) { + roleMapper.insert(roleDTO.toDO()); + return ResponseData.create().success(); + } + + @Override + public ResponseData addUser(SysUserDTO userDTO) { + userMapper.insert(userDTO.toDO()); + return ResponseData.create().success(); + } +} diff --git a/src/main/resources/db/schema-h2.sql b/src/main/resources/db/schema-h2.sql index 355ffc1..305ec7d 100644 --- a/src/main/resources/db/schema-h2.sql +++ b/src/main/resources/db/schema-h2.sql @@ -34,4 +34,35 @@ CREATE TABLE IF NOT EXISTS T_CLUSTER_INFO UPDATE_TIME TIMESTAMP NOT NULL DEFAULT NOW() COMMENT '更新时间', PRIMARY KEY (ID), UNIQUE (CLUSTER_NAME) +); + +-- 登录用户的角色权限配置 +CREATE TABLE IF NOT EXISTS t_sys_permission +( + ID IDENTITY NOT NULL COMMENT '主键ID', + name varchar(100) DEFAULT NULL COMMENT '权限名称', + type tinyint(1) NOT NULL DEFAULT 0 COMMENT '权限类型: 0:菜单,1:按钮', + parent_id bigint(20) DEFAULT NULL COMMENT '所属父权限ID', + permission varchar(100) DEFAULT NULL COMMENT '权限字符串', + PRIMARY KEY (id) +); + +CREATE TABLE IF NOT EXISTS t_sys_role +( + ID IDENTITY NOT NULL COMMENT '主键ID', + role_name varchar(100) NOT NULL COMMENT '角色名称', + description varchar(100) DEFAULT NULL COMMENT '角色描述', + permission_ids varchar(500) DEFAULT NULL COMMENT '分配的权限ID', + PRIMARY KEY (id) +); + +CREATE TABLE IF NOT EXISTS t_sys_user +( + ID IDENTITY NOT NULL COMMENT '主键ID', + username varchar(100) DEFAULT NULL COMMENT '用户名', + password varchar(100) DEFAULT NULL COMMENT '用户密码', + salt varchar(100) DEFAULT NULL COMMENT '加密的盐值', + role_ids varchar(100) DEFAULT NULL COMMENT '分配角色的ID', + PRIMARY KEY (id), + UNIQUE (username) ); \ No newline at end of file diff --git a/ui/src/App.vue b/ui/src/App.vue index db6fde5..a07c4a0 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -16,6 +16,8 @@ |Acl |用户 + |运维 集群:{{ clusterName }} diff --git a/ui/src/router/index.js b/ui/src/router/index.js index d14b862..d69f292 100644 --- a/ui/src/router/index.js +++ b/ui/src/router/index.js @@ -55,6 +55,12 @@ const routes = [ component: () => import(/* webpackChunkName: "cluster" */ "../views/quota/ClientQuota.vue"), }, + { + path: "/user-page", + name: "UserManage", + component: () => + import(/* webpackChunkName: "cluster" */ "../views/user/UserManage.vue"), + }, ]; const router = new VueRouter({ diff --git a/ui/src/views/user/UserManage.vue b/ui/src/views/user/UserManage.vue new file mode 100644 index 0000000..3cd1f78 --- /dev/null +++ b/ui/src/views/user/UserManage.vue @@ -0,0 +1,35 @@ + + + + + From af52e6bc6144ce0e3cedb6b60aaa3055184cdca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=99=93=E4=B8=9C?= <763795151@qq.com> Date: Mon, 17 Apr 2023 22:24:51 +0800 Subject: [PATCH 02/13] =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=B1=95=E7=A4=BA.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../console/beans/vo/SysPermissionVO.java | 40 +++++++ .../controller/UserManageController.java | 10 +- .../console/service/UserManageService.java | 2 + .../service/impl/UserManageServiceImpl.java | 61 +++++++++++ src/main/resources/logback-test.xml | 4 +- ui/src/utils/api.js | 11 ++ ui/src/views/user/Permission.vue | 103 ++++++++++++++++++ ui/src/views/user/UserManage.vue | 17 ++- 8 files changed, 232 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/xuxd/kafka/console/beans/vo/SysPermissionVO.java create mode 100644 ui/src/views/user/Permission.vue diff --git a/src/main/java/com/xuxd/kafka/console/beans/vo/SysPermissionVO.java b/src/main/java/com/xuxd/kafka/console/beans/vo/SysPermissionVO.java new file mode 100644 index 0000000..1c7eb92 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/beans/vo/SysPermissionVO.java @@ -0,0 +1,40 @@ +package com.xuxd.kafka.console.beans.vo; + +import com.xuxd.kafka.console.beans.dos.SysPermissionDO; +import lombok.Data; + +import java.util.List; + +/** + * @author: xuxd + * @date: 2023/4/17 21:18 + **/ +@Data +public class SysPermissionVO { + + private String name; + + /** + * 权限类型: 0:菜单,1:按钮 + */ + private Integer type; + + private Long parentId; + + private String permission; + + private Long key; + + private List children; + + public static SysPermissionVO from(SysPermissionDO permissionDO) { + SysPermissionVO permissionVO = new SysPermissionVO(); + + permissionVO.setPermission(permissionDO.getPermission()); + permissionVO.setType(permissionDO.getType()); + permissionVO.setName(permissionDO.getName()); + permissionVO.setParentId(permissionDO.getParentId()); + permissionVO.setKey(permissionDO.getId()); + return permissionVO; + } +} 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 f10074d..a9c5639 100644 --- a/src/main/java/com/xuxd/kafka/console/controller/UserManageController.java +++ b/src/main/java/com/xuxd/kafka/console/controller/UserManageController.java @@ -5,10 +5,7 @@ import com.xuxd.kafka.console.beans.dto.SysPermissionDTO; import com.xuxd.kafka.console.beans.dto.SysRoleDTO; import com.xuxd.kafka.console.beans.dto.SysUserDTO; import com.xuxd.kafka.console.service.UserManageService; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; /** * @author: xuxd @@ -41,4 +38,9 @@ public class UserManageController { public Object addPermission(@RequestBody SysPermissionDTO permissionDTO) { return userManageService.addPermission(permissionDTO); } + + @GetMapping("/permission") + public Object selectPermission() { + return userManageService.selectPermission(); + } } diff --git a/src/main/java/com/xuxd/kafka/console/service/UserManageService.java b/src/main/java/com/xuxd/kafka/console/service/UserManageService.java index a6677e5..2b7aafc 100644 --- a/src/main/java/com/xuxd/kafka/console/service/UserManageService.java +++ b/src/main/java/com/xuxd/kafka/console/service/UserManageService.java @@ -21,4 +21,6 @@ public interface UserManageService { ResponseData addRole(SysRoleDTO roleDTO); ResponseData addUser(SysUserDTO userDTO); + + ResponseData selectPermission(); } diff --git a/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java b/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java index dc85b96..793f19a 100644 --- a/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java +++ b/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java @@ -1,9 +1,12 @@ package com.xuxd.kafka.console.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.xuxd.kafka.console.beans.ResponseData; +import com.xuxd.kafka.console.beans.dos.SysPermissionDO; import com.xuxd.kafka.console.beans.dto.SysPermissionDTO; import com.xuxd.kafka.console.beans.dto.SysRoleDTO; import com.xuxd.kafka.console.beans.dto.SysUserDTO; +import com.xuxd.kafka.console.beans.vo.SysPermissionVO; import com.xuxd.kafka.console.dao.SysPermissionMapper; import com.xuxd.kafka.console.dao.SysRoleMapper; import com.xuxd.kafka.console.dao.SysUserMapper; @@ -12,6 +15,9 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.ObjectProvider; import org.springframework.stereotype.Service; +import java.util.*; +import java.util.stream.Collectors; + /** * @author: xuxd * @date: 2023/4/11 21:24 @@ -51,4 +57,59 @@ public class UserManageServiceImpl implements UserManageService { userMapper.insert(userDTO.toDO()); return ResponseData.create().success(); } + + @Override + public ResponseData selectPermission() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + + List permissionDOS = permissionMapper.selectList(queryWrapper); + List vos = new ArrayList<>(); + Map posMap = new HashMap<>(); + Map voMap = new HashMap<>(); + + Iterator iterator = permissionDOS.iterator(); + while (iterator.hasNext()) { + SysPermissionDO permissionDO = iterator.next(); + if (permissionDO.getParentId() == null) { + // 菜单 + SysPermissionVO vo = SysPermissionVO.from(permissionDO); + vos.add(vo); + int index = vos.size() - 1; + // 记录位置 + posMap.put(permissionDO.getId(), index); + iterator.remove(); + } + } + // 上面把菜单都处理过了 + while (!permissionDOS.isEmpty()) { + iterator = permissionDOS.iterator(); + while (iterator.hasNext()) { + SysPermissionDO permissionDO = iterator.next(); + Long parentId = permissionDO.getParentId(); + if (posMap.containsKey(parentId)) { + // 菜单下的按扭 + SysPermissionVO vo = SysPermissionVO.from(permissionDO); + Integer index = posMap.get(parentId); + SysPermissionVO menuVO = vos.get(index); + if (menuVO.getChildren() == null) { + menuVO.setChildren(new ArrayList<>()); + } + menuVO.getChildren().add(vo); + voMap.put(permissionDO.getId(), vo); + iterator.remove(); + } else if (voMap.containsKey(parentId)) { + // 按钮下的按扭 + SysPermissionVO vo = SysPermissionVO.from(permissionDO); + SysPermissionVO buttonVO = voMap.get(parentId); + if (buttonVO.getChildren() == null) { + buttonVO.setChildren(new ArrayList<>()); + } + buttonVO.getChildren().add(vo); + voMap.put(permissionDO.getId(), vo); + iterator.remove(); + } + } + } + return ResponseData.create().data(vos).success(); + } } diff --git a/src/main/resources/logback-test.xml b/src/main/resources/logback-test.xml index cf8f74a..7783f53 100644 --- a/src/main/resources/logback-test.xml +++ b/src/main/resources/logback-test.xml @@ -3,9 +3,9 @@ - + - + diff --git a/ui/src/utils/api.js b/ui/src/utils/api.js index 31b747f..09d5b09 100644 --- a/ui/src/utils/api.js +++ b/ui/src/utils/api.js @@ -307,4 +307,15 @@ export const KafkaClientQuotaApi = { url: "/client/quota", method: "delete", }, +}; + +export const UserManageApi = { + getPermissions: { + url: "/sys/user/manage/permission", + method: "get", + }, + addPermission: { + url: "/sys/user/manage/permission", + method: "post", + }, }; \ No newline at end of file diff --git a/ui/src/views/user/Permission.vue b/ui/src/views/user/Permission.vue new file mode 100644 index 0000000..a18f84e --- /dev/null +++ b/ui/src/views/user/Permission.vue @@ -0,0 +1,103 @@ + + + + + diff --git a/ui/src/views/user/UserManage.vue b/ui/src/views/user/UserManage.vue index 3cd1f78..9720a9d 100644 --- a/ui/src/views/user/UserManage.vue +++ b/ui/src/views/user/UserManage.vue @@ -2,24 +2,22 @@
- - - - + + + - - +
From a37664f6d5589f394ae91e7aaa81d22ffc175438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=99=93=E4=B8=9C?= <763795151@qq.com> Date: Wed, 19 Apr 2023 22:10:08 +0800 Subject: [PATCH 03/13] =?UTF-8?q?=E8=A7=92=E8=89=B2=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E9=9B=8F=E5=BD=A2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kafka/console/beans/vo/SysRoleVO.java | 26 +++ .../controller/UserManageController.java | 5 + .../console/service/UserManageService.java | 2 + .../service/impl/UserManageServiceImpl.java | 8 + ui/src/utils/api.js | 4 + ui/src/views/user/Role.vue | 171 ++++++++++++++++++ ui/src/views/user/UserManage.vue | 7 +- 7 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/xuxd/kafka/console/beans/vo/SysRoleVO.java create mode 100644 ui/src/views/user/Role.vue diff --git a/src/main/java/com/xuxd/kafka/console/beans/vo/SysRoleVO.java b/src/main/java/com/xuxd/kafka/console/beans/vo/SysRoleVO.java new file mode 100644 index 0000000..3bcc0a7 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/beans/vo/SysRoleVO.java @@ -0,0 +1,26 @@ +package com.xuxd.kafka.console.beans.vo; + +import com.xuxd.kafka.console.beans.dos.SysRoleDO; +import lombok.Data; + +/** + * @author: xuxd + * @date: 2023/4/19 21:12 + **/ +@Data +public class SysRoleVO { + + private String roleName; + + private String description; + + private String permissionIds; + + public static SysRoleVO from(SysRoleDO roleDO) { + SysRoleVO roleVO = new SysRoleVO(); + roleVO.setRoleName(roleDO.getRoleName()); + roleVO.setDescription(roleDO.getDescription()); + roleVO.setPermissionIds(roleDO.getPermissionIds()); + return roleVO; + } +} 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 a9c5639..c7e6424 100644 --- a/src/main/java/com/xuxd/kafka/console/controller/UserManageController.java +++ b/src/main/java/com/xuxd/kafka/console/controller/UserManageController.java @@ -39,6 +39,11 @@ public class UserManageController { return userManageService.addPermission(permissionDTO); } + @GetMapping("/role") + public Object selectRole() { + return userManageService.selectRole(); + } + @GetMapping("/permission") public Object selectPermission() { return userManageService.selectPermission(); diff --git a/src/main/java/com/xuxd/kafka/console/service/UserManageService.java b/src/main/java/com/xuxd/kafka/console/service/UserManageService.java index 2b7aafc..1ae4a8b 100644 --- a/src/main/java/com/xuxd/kafka/console/service/UserManageService.java +++ b/src/main/java/com/xuxd/kafka/console/service/UserManageService.java @@ -22,5 +22,7 @@ public interface UserManageService { ResponseData addUser(SysUserDTO userDTO); + ResponseData selectRole(); + ResponseData selectPermission(); } diff --git a/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java b/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java index 793f19a..29615ba 100644 --- a/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java +++ b/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java @@ -3,10 +3,12 @@ package com.xuxd.kafka.console.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.xuxd.kafka.console.beans.ResponseData; import com.xuxd.kafka.console.beans.dos.SysPermissionDO; +import com.xuxd.kafka.console.beans.dos.SysRoleDO; import com.xuxd.kafka.console.beans.dto.SysPermissionDTO; import com.xuxd.kafka.console.beans.dto.SysRoleDTO; import com.xuxd.kafka.console.beans.dto.SysUserDTO; import com.xuxd.kafka.console.beans.vo.SysPermissionVO; +import com.xuxd.kafka.console.beans.vo.SysRoleVO; import com.xuxd.kafka.console.dao.SysPermissionMapper; import com.xuxd.kafka.console.dao.SysRoleMapper; import com.xuxd.kafka.console.dao.SysUserMapper; @@ -58,6 +60,12 @@ public class UserManageServiceImpl implements UserManageService { return ResponseData.create().success(); } + @Override + public ResponseData selectRole() { + List dos = roleMapper.selectList(new QueryWrapper<>()); + return ResponseData.create().data(dos.stream().map(SysRoleVO::from).collect(Collectors.toList())).success(); + } + @Override public ResponseData selectPermission() { QueryWrapper queryWrapper = new QueryWrapper<>(); diff --git a/ui/src/utils/api.js b/ui/src/utils/api.js index 09d5b09..2bfd408 100644 --- a/ui/src/utils/api.js +++ b/ui/src/utils/api.js @@ -318,4 +318,8 @@ export const UserManageApi = { url: "/sys/user/manage/permission", method: "post", }, + getRole: { + url: "/sys/user/manage/role", + method: "get", + }, }; \ No newline at end of file diff --git a/ui/src/views/user/Role.vue b/ui/src/views/user/Role.vue new file mode 100644 index 0000000..f9267c9 --- /dev/null +++ b/ui/src/views/user/Role.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/ui/src/views/user/UserManage.vue b/ui/src/views/user/UserManage.vue index 9720a9d..0e2f501 100644 --- a/ui/src/views/user/UserManage.vue +++ b/ui/src/views/user/UserManage.vue @@ -3,7 +3,9 @@ - + + + @@ -15,9 +17,10 @@ + + diff --git a/ui/src/views/user/Role.vue b/ui/src/views/user/Role.vue index 4abda75..78a9b0a 100644 --- a/ui/src/views/user/Role.vue +++ b/ui/src/views/user/Role.vue @@ -24,7 +24,7 @@ title="确定删除角色?" ok-text="确认" cancel-text="取消" - @confirm="deleteRole(item.id)" + @confirm="deleteRole(item)" > @@ -35,7 +35,7 @@ - 新增角色 + 新增角色 @@ -212,16 +212,23 @@ export default { this.selectedPermissions.push(menu); }); }, - deleteRole(id) { + deleteRole(role) { + if (role.adding) { + this.roles.pop(); + return; + } this.loading = true; request({ - url: UserManageApi.deleteRole.url + "?id=" + id, + url: UserManageApi.deleteRole.url + "?id=" + role.id, method: UserManageApi.deleteRole.method, }).then((res) => { this.loading = false; if (res.code == 0) { this.$message.success(res.msg); this.getRoles(); + if (role.id == this.selectedRole.id) { + this.selectedRole = {}; + } } else { notification.error({ message: "error", @@ -230,6 +237,15 @@ export default { } }); }, + addRole() { + const role = { + roleName: "角色名称", + description: "角色描述", + adding: true, + }; + this.roles.push(role); + this.selected(role); + }, onSave() { this.form.validateFields((err, values) => { if (!err) { diff --git a/ui/src/views/user/User.vue b/ui/src/views/user/User.vue new file mode 100644 index 0000000..9000cf0 --- /dev/null +++ b/ui/src/views/user/User.vue @@ -0,0 +1,225 @@ + + + + + diff --git a/ui/src/views/user/UserManage.vue b/ui/src/views/user/UserManage.vue index 0e2f501..8fd7b63 100644 --- a/ui/src/views/user/UserManage.vue +++ b/ui/src/views/user/UserManage.vue @@ -2,7 +2,9 @@
- + + + @@ -18,9 +20,10 @@ + + diff --git a/ui/src/views/user/CreateUser.vue b/ui/src/views/user/CreateUser.vue index 6346c2f..829a154 100644 --- a/ui/src/views/user/CreateUser.vue +++ b/ui/src/views/user/CreateUser.vue @@ -95,7 +95,7 @@ export default { this.loading = false; if (res.code == 0) { this.$message.success(res.msg); - this.$emit("closeCreateUserDialog", { refresh: true }); + this.$emit("closeCreateUserDialog", { refresh: true, data: res.data }); } else { notification.error({ message: "error", diff --git a/ui/src/views/user/UpdateUserRole.vue b/ui/src/views/user/UpdateUserRole.vue new file mode 100644 index 0000000..2c78034 --- /dev/null +++ b/ui/src/views/user/UpdateUserRole.vue @@ -0,0 +1,138 @@ + + + + + diff --git a/ui/src/views/user/User.vue b/ui/src/views/user/User.vue index 9000cf0..e0eab23 100644 --- a/ui/src/views/user/User.vue +++ b/ui/src/views/user/User.vue @@ -53,8 +53,22 @@ >删除 - 重置密码 + + 重置密码 + + + 分配角色
@@ -62,6 +76,16 @@ @closeCreateUserDialog="closeCreateUserDialog" :visible="showCreateUserDialog" > + +
@@ -72,10 +96,12 @@ import request from "@/utils/request"; import notification from "ant-design-vue/lib/notification"; import { UserManageApi } from "@/utils/api"; import CreateUser from "@/views/user/CreateUser.vue"; +import MessageBox from "@/views/components/MessageBox.vue"; +import UpdateUserRole from "@/views/user/UpdateUserRole.vue"; export default { name: "User", - components: { CreateUser }, + components: { CreateUser, MessageBox, UpdateUserRole }, props: { topicList: { type: Array, @@ -89,6 +115,10 @@ export default { filteredData: [], filterUsername: "", showCreateUserDialog: false, + showMessageBox: false, + showUpdateUserRole: false, + messageBoxContent: "", + selectUser: {}, columns: [ { title: "用户名", @@ -97,8 +127,8 @@ export default { }, { title: "角色", - dataIndex: "roleIds", - key: "roleIds", + dataIndex: "roleNames", + key: "roleNames", }, { title: "操作", @@ -150,8 +180,23 @@ export default { this.showCreateUserDialog = false; if (p.refresh) { this.refresh(); + this.messageBoxContent = "用户初始密码:" + p.data; + this.showMessageBox = true; } }, + openUpdateUserRoleDialog(user) { + this.selectUser = user; + this.showUpdateUserRole = true; + }, + closeUpdateUserRoleDialog(p) { + this.showUpdateUserRole = false; + if (p.refresh) { + this.refresh(); + } + }, + closeMessageBox() { + this.showMessageBox = false; + }, deleteUser(user) { this.loading = true; request({ @@ -169,6 +214,27 @@ export default { } }); }, + resetPassword(record) { + this.loading = true; + const params = Object.assign({}, record); + params.resetPassword = true; + request({ + url: UserManageApi.addOrUpdateUser.url, + method: UserManageApi.addOrUpdateUser.method, + data: params, + }).then((res) => { + this.loading = false; + if (res.code == 0) { + this.messageBoxContent = "密码重置成功,新密码:" + res.data; + this.showMessageBox = true; + } else { + notification.error({ + message: "error", + description: res.msg, + }); + } + }); + }, }, created() { this.handleSearch(); @@ -222,4 +288,8 @@ export default { margin-bottom: 5px; margin-top: 5px; } + +.operation-btn { + margin-right: 3%; +} From be8e5676845b5433d48c59d5403ef4fec4ab3f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=99=93=E4=B8=9C?= <763795151@qq.com> Date: Tue, 9 May 2023 20:44:54 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=E4=B8=AA=E4=BA=BA=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=AF=86=E7=A0=81.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/UserManageController.java | 6 ++ .../console/service/UserManageService.java | 2 + .../service/impl/UserManageServiceImpl.java | 15 +++ ui/src/components/HelloWorld.vue | 32 ------- ui/src/{views => }/components/MessageBox.vue | 0 ui/src/utils/api.js | 4 + ui/src/views/user/CreateUser.vue | 3 + ui/src/views/user/UpdateUserRole.vue | 3 + ui/src/views/user/User.vue | 2 +- ui/src/views/user/UserManage.vue | 7 +- ui/src/views/user/UserSetting.vue | 92 +++++++++++++++++++ 11 files changed, 131 insertions(+), 35 deletions(-) delete mode 100644 ui/src/components/HelloWorld.vue rename ui/src/{views => }/components/MessageBox.vue (100%) create mode 100644 ui/src/views/user/UserSetting.vue 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 aabd594..bf5d62c 100644 --- a/src/main/java/com/xuxd/kafka/console/controller/UserManageController.java +++ b/src/main/java/com/xuxd/kafka/console/controller/UserManageController.java @@ -71,4 +71,10 @@ public class UserManageController { public Object deleteUser(@RequestParam Long id) { return userManageService.deleteUser(id); } + + @ControllerLog("更新密码") + @PostMapping("/user/password") + public Object updatePassword(@RequestBody SysUserDTO userDTO) { + return userManageService.updatePassword(userDTO); + } } diff --git a/src/main/java/com/xuxd/kafka/console/service/UserManageService.java b/src/main/java/com/xuxd/kafka/console/service/UserManageService.java index 9b41083..b999662 100644 --- a/src/main/java/com/xuxd/kafka/console/service/UserManageService.java +++ b/src/main/java/com/xuxd/kafka/console/service/UserManageService.java @@ -35,4 +35,6 @@ public interface UserManageService { ResponseData deleteRole(Long id); ResponseData deleteUser(Long id); + + ResponseData updatePassword(SysUserDTO userDTO); } diff --git a/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java b/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java index eaa6a5c..c0255f2 100644 --- a/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java +++ b/src/main/java/com/xuxd/kafka/console/service/impl/UserManageServiceImpl.java @@ -192,6 +192,12 @@ public class UserManageServiceImpl implements UserManageService { @Override public ResponseData deleteRole(Long id) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq(true, "role_ids", id); + Integer count = userMapper.selectCount(queryWrapper); + if (count > 0) { + return ResponseData.create().failed("存在用户被分配为当前角色,不允许删除"); + } roleMapper.deleteById(id); return ResponseData.create().success(); } @@ -201,4 +207,13 @@ public class UserManageServiceImpl implements UserManageService { userMapper.deleteById(id); return ResponseData.create().success(); } + + @Override + public ResponseData updatePassword(SysUserDTO userDTO) { + SysUserDO userDO = userDTO.toDO(); + userDO.setSalt(UUIDStrUtil.random()); + userDO.setPassword(UUIDStrUtil.generate(userDTO.getPassword(), userDO.getSalt())); + userMapper.updateById(userDO); + return ResponseData.create().success(); + } } diff --git a/ui/src/components/HelloWorld.vue b/ui/src/components/HelloWorld.vue deleted file mode 100644 index 0a5f13a..0000000 --- a/ui/src/components/HelloWorld.vue +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - diff --git a/ui/src/views/components/MessageBox.vue b/ui/src/components/MessageBox.vue similarity index 100% rename from ui/src/views/components/MessageBox.vue rename to ui/src/components/MessageBox.vue diff --git a/ui/src/utils/api.js b/ui/src/utils/api.js index 89b3c46..b098723 100644 --- a/ui/src/utils/api.js +++ b/ui/src/utils/api.js @@ -342,4 +342,8 @@ export const UserManageApi = { url: "/sys/user/manage/user", method: "delete", }, + updatePassword: { + url: "/sys/user/manage/user/password", + method: "post", + }, }; \ No newline at end of file diff --git a/ui/src/views/user/CreateUser.vue b/ui/src/views/user/CreateUser.vue index 829a154..e3e4c53 100644 --- a/ui/src/views/user/CreateUser.vue +++ b/ui/src/views/user/CreateUser.vue @@ -79,6 +79,9 @@ export default { watch: { visible(v) { this.show = v; + if (this.show) { + this.getRoles(); + } }, }, methods: { diff --git a/ui/src/views/user/UpdateUserRole.vue b/ui/src/views/user/UpdateUserRole.vue index 2c78034..62f0426 100644 --- a/ui/src/views/user/UpdateUserRole.vue +++ b/ui/src/views/user/UpdateUserRole.vue @@ -76,6 +76,9 @@ export default { watch: { visible(v) { this.show = v; + if (this.show) { + this.getRoles(); + } }, }, methods: { diff --git a/ui/src/views/user/User.vue b/ui/src/views/user/User.vue index e0eab23..7f97d1c 100644 --- a/ui/src/views/user/User.vue +++ b/ui/src/views/user/User.vue @@ -96,7 +96,7 @@ import request from "@/utils/request"; import notification from "ant-design-vue/lib/notification"; import { UserManageApi } from "@/utils/api"; import CreateUser from "@/views/user/CreateUser.vue"; -import MessageBox from "@/views/components/MessageBox.vue"; +import MessageBox from "@/components/MessageBox.vue"; import UpdateUserRole from "@/views/user/UpdateUserRole.vue"; export default { diff --git a/ui/src/views/user/UserManage.vue b/ui/src/views/user/UserManage.vue index 8fd7b63..ea63ecf 100644 --- a/ui/src/views/user/UserManage.vue +++ b/ui/src/views/user/UserManage.vue @@ -11,7 +11,9 @@ - + + + @@ -21,9 +23,10 @@ import Permission from "@/views/user/Permission.vue"; import Role from "@/views/user/Role.vue"; import User from "@/views/user/User.vue"; +import UserSetting from "@/views/user/UserSetting.vue"; export default { name: "UserManage", - components: { Permission, Role, User }, + components: { Permission, Role, User, UserSetting }, data() { return { loading: false, diff --git a/ui/src/views/user/UserSetting.vue b/ui/src/views/user/UserSetting.vue new file mode 100644 index 0000000..a5bfbc0 --- /dev/null +++ b/ui/src/views/user/UserSetting.vue @@ -0,0 +1,92 @@ + + + + + From 435a5ca2bc6938354ff1ee5a8d5ec5481f1c481e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=99=93=E4=B8=9C?= <763795151@qq.com> Date: Sun, 14 May 2023 21:25:13 +0800 Subject: [PATCH 09/13] =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xuxd/kafka/console/beans/Credentials.java | 21 ++++ .../xuxd/kafka/console/beans/LoginResult.java | 13 +++ .../kafka/console/beans/dto/LoginUserDTO.java | 15 +++ .../xuxd/kafka/console/config/AuthConfig.java | 21 ++++ .../console/controller/AuthController.java | 36 ++++++ .../xuxd/kafka/console/dao/SysUserMapper.java | 2 + .../kafka/console/interceptor/AuthFilter.java | 64 +++++++++++ .../console/interceptor/ContextSetFilter.java | 2 + .../kafka/console/service/AuthService.java | 13 +++ .../console/service/impl/AuthServiceImpl.java | 54 +++++++++ .../xuxd/kafka/console/utils/AuthUtil.java | 54 +++++++++ .../com/xuxd/kafka/console/utils/MD5Util.java | 32 ++++++ src/main/resources/application.yml | 6 + ui/src/App.vue | 57 ++++++---- ui/src/router/index.js | 58 +++++++++- ui/src/store/index.js | 11 +- ui/src/store/mutation-types.js | 5 + ui/src/utils/api.js | 11 ++ ui/src/utils/request.js | 26 ++++- ui/src/views/login/Login.vue | 103 ++++++++++++++++++ 20 files changed, 575 insertions(+), 29 deletions(-) create mode 100644 src/main/java/com/xuxd/kafka/console/beans/Credentials.java create mode 100644 src/main/java/com/xuxd/kafka/console/beans/LoginResult.java create mode 100644 src/main/java/com/xuxd/kafka/console/beans/dto/LoginUserDTO.java create mode 100644 src/main/java/com/xuxd/kafka/console/config/AuthConfig.java create mode 100644 src/main/java/com/xuxd/kafka/console/controller/AuthController.java create mode 100644 src/main/java/com/xuxd/kafka/console/interceptor/AuthFilter.java create mode 100644 src/main/java/com/xuxd/kafka/console/service/AuthService.java create mode 100644 src/main/java/com/xuxd/kafka/console/service/impl/AuthServiceImpl.java create mode 100644 src/main/java/com/xuxd/kafka/console/utils/AuthUtil.java create mode 100644 src/main/java/com/xuxd/kafka/console/utils/MD5Util.java create mode 100644 ui/src/views/login/Login.vue diff --git a/src/main/java/com/xuxd/kafka/console/beans/Credentials.java b/src/main/java/com/xuxd/kafka/console/beans/Credentials.java new file mode 100644 index 0000000..fe6db9c --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/beans/Credentials.java @@ -0,0 +1,21 @@ +package com.xuxd.kafka.console.beans; + +import lombok.Data; + +/** + * @author: xuxd + * @date: 2023/5/14 19:37 + **/ +@Data +public class Credentials { + + public static final Credentials INVALID = new Credentials(); + + private String username; + + private long expiration; + + public boolean isInvalid() { + return this == INVALID; + } +} diff --git a/src/main/java/com/xuxd/kafka/console/beans/LoginResult.java b/src/main/java/com/xuxd/kafka/console/beans/LoginResult.java new file mode 100644 index 0000000..75faeaa --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/beans/LoginResult.java @@ -0,0 +1,13 @@ +package com.xuxd.kafka.console.beans; + +import lombok.Data; + +/** + * @author: xuxd + * @date: 2023/5/14 20:44 + **/ +@Data +public class LoginResult { + + private String token; +} diff --git a/src/main/java/com/xuxd/kafka/console/beans/dto/LoginUserDTO.java b/src/main/java/com/xuxd/kafka/console/beans/dto/LoginUserDTO.java new file mode 100644 index 0000000..b4fc2f4 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/beans/dto/LoginUserDTO.java @@ -0,0 +1,15 @@ +package com.xuxd.kafka.console.beans.dto; + +import lombok.Data; + +/** + * @author: xuxd + * @date: 2023/5/14 18:59 + **/ +@Data +public class LoginUserDTO { + + private String username; + + private String password; +} diff --git a/src/main/java/com/xuxd/kafka/console/config/AuthConfig.java b/src/main/java/com/xuxd/kafka/console/config/AuthConfig.java new file mode 100644 index 0000000..04b2d42 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/config/AuthConfig.java @@ -0,0 +1,21 @@ +package com.xuxd.kafka.console.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @author: xuxd + * @date: 2023/5/9 21:08 + **/ +@Data +@Configuration +@ConfigurationProperties(prefix = "auth") +public class AuthConfig { + + private boolean enable; + + private String secret = "kafka-console-ui-default-secret"; + + private long expireHours; +} diff --git a/src/main/java/com/xuxd/kafka/console/controller/AuthController.java b/src/main/java/com/xuxd/kafka/console/controller/AuthController.java new file mode 100644 index 0000000..f71e806 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/controller/AuthController.java @@ -0,0 +1,36 @@ +package com.xuxd.kafka.console.controller; + +import com.xuxd.kafka.console.beans.ResponseData; +import com.xuxd.kafka.console.beans.dto.LoginUserDTO; +import com.xuxd.kafka.console.config.AuthConfig; +import com.xuxd.kafka.console.service.AuthService; +import org.springframework.web.bind.annotation.*; + +/** + * @author: xuxd + * @date: 2023/5/11 18:54 + **/ +@RestController +@RequestMapping("/auth") +public class AuthController { + + + private final AuthConfig authConfig; + + private final AuthService authService; + + public AuthController(AuthConfig authConfig, AuthService authService) { + this.authConfig = authConfig; + this.authService = authService; + } + + @GetMapping("/enable") + public boolean enable() { + return authConfig.isEnable(); + } + + @PostMapping("/login") + public ResponseData login(@RequestBody LoginUserDTO userDTO) { + return authService.login(userDTO); + } +} diff --git a/src/main/java/com/xuxd/kafka/console/dao/SysUserMapper.java b/src/main/java/com/xuxd/kafka/console/dao/SysUserMapper.java index 7a3af87..73a0060 100644 --- a/src/main/java/com/xuxd/kafka/console/dao/SysUserMapper.java +++ b/src/main/java/com/xuxd/kafka/console/dao/SysUserMapper.java @@ -2,10 +2,12 @@ package com.xuxd.kafka.console.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.xuxd.kafka.console.beans.dos.SysUserDO; +import org.apache.ibatis.annotations.Mapper; /** * @author: xuxd * @date: 2023/4/11 21:22 **/ +@Mapper public interface SysUserMapper extends BaseMapper { } diff --git a/src/main/java/com/xuxd/kafka/console/interceptor/AuthFilter.java b/src/main/java/com/xuxd/kafka/console/interceptor/AuthFilter.java new file mode 100644 index 0000000..0a32555 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/interceptor/AuthFilter.java @@ -0,0 +1,64 @@ +package com.xuxd.kafka.console.interceptor; + +import com.xuxd.kafka.console.beans.Credentials; +import com.xuxd.kafka.console.config.AuthConfig; +import com.xuxd.kafka.console.utils.AuthUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.annotation.Order; +import org.springframework.http.HttpStatus; + +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author: xuxd + * @date: 2023/5/9 21:20 + **/ +@Order(1) +@WebFilter(filterName = "auth-filter", urlPatterns = {"/*"}) +@Slf4j +public class AuthFilter implements Filter { + + private final AuthConfig authConfig; + + private final String TOKEN_HEADER = "X-Auth-Token"; + + private final String AUTH_URI_PREFIX = "/auth"; + + public AuthFilter(AuthConfig authConfig) { + this.authConfig = authConfig; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + if (!authConfig.isEnable()) { + filterChain.doFilter(servletRequest, servletResponse); + return; + } + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + String accessToken = request.getHeader(TOKEN_HEADER); + + String requestURI = request.getRequestURI(); + if (requestURI.startsWith(AUTH_URI_PREFIX)) { + filterChain.doFilter(servletRequest, servletResponse); + return; + } + if (StringUtils.isEmpty(accessToken)) { + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + return; + } + + Credentials credentials = AuthUtil.parseToken(authConfig.getSecret(), accessToken); + if (credentials.isInvalid()) { + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + return; + } + + filterChain.doFilter(servletRequest, servletResponse); + } +} diff --git a/src/main/java/com/xuxd/kafka/console/interceptor/ContextSetFilter.java b/src/main/java/com/xuxd/kafka/console/interceptor/ContextSetFilter.java index cd5acf9..d336f9c 100644 --- a/src/main/java/com/xuxd/kafka/console/interceptor/ContextSetFilter.java +++ b/src/main/java/com/xuxd/kafka/console/interceptor/ContextSetFilter.java @@ -9,6 +9,7 @@ import com.xuxd.kafka.console.utils.ConvertUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; import org.springframework.http.MediaType; import javax.servlet.*; @@ -24,6 +25,7 @@ import java.util.Set; * @author xuxd * @date 2022-01-05 19:56:25 **/ +@Order(100) @WebFilter(filterName = "context-set-filter", urlPatterns = {"/acl/*", "/user/*", "/cluster/*", "/config/*", "/consumer/*", "/message/*", "/topic/*", "/op/*", "/client/*"}) @Slf4j public class ContextSetFilter implements Filter { diff --git a/src/main/java/com/xuxd/kafka/console/service/AuthService.java b/src/main/java/com/xuxd/kafka/console/service/AuthService.java new file mode 100644 index 0000000..c437dc1 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/service/AuthService.java @@ -0,0 +1,13 @@ +package com.xuxd.kafka.console.service; + +import com.xuxd.kafka.console.beans.ResponseData; +import com.xuxd.kafka.console.beans.dto.LoginUserDTO; + +/** + * @author: xuxd + * @date: 2023/5/14 19:00 + **/ +public interface AuthService { + + ResponseData login(LoginUserDTO userDTO); +} diff --git a/src/main/java/com/xuxd/kafka/console/service/impl/AuthServiceImpl.java b/src/main/java/com/xuxd/kafka/console/service/impl/AuthServiceImpl.java new file mode 100644 index 0000000..d44d4af --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/service/impl/AuthServiceImpl.java @@ -0,0 +1,54 @@ +package com.xuxd.kafka.console.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.xuxd.kafka.console.beans.Credentials; +import com.xuxd.kafka.console.beans.LoginResult; +import com.xuxd.kafka.console.beans.ResponseData; +import com.xuxd.kafka.console.beans.dos.SysUserDO; +import com.xuxd.kafka.console.beans.dto.LoginUserDTO; +import com.xuxd.kafka.console.config.AuthConfig; +import com.xuxd.kafka.console.dao.SysUserMapper; +import com.xuxd.kafka.console.service.AuthService; +import com.xuxd.kafka.console.utils.AuthUtil; +import com.xuxd.kafka.console.utils.UUIDStrUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * @author: xuxd + * @date: 2023/5/14 19:01 + **/ +@Slf4j +@Service +public class AuthServiceImpl implements AuthService { + + private final SysUserMapper userMapper; + + private final AuthConfig authConfig; + + public AuthServiceImpl(SysUserMapper userMapper, AuthConfig authConfig) { + this.userMapper = userMapper; + this.authConfig = authConfig; + } + + @Override + public ResponseData login(LoginUserDTO userDTO) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("username", userDTO.getUsername()); + SysUserDO userDO = userMapper.selectOne(queryWrapper); + if (userDO == null) { + return ResponseData.create().failed("用户名/密码不正确"); + } + String encrypt = UUIDStrUtil.generate(userDTO.getPassword(), userDO.getSalt()); + if (!userDO.getPassword().equals(encrypt)) { + return ResponseData.create().failed("用户名/密码不正确"); + } + Credentials credentials = new Credentials(); + credentials.setUsername(userDO.getUsername()); + credentials.setExpiration(System.currentTimeMillis() + authConfig.getExpireHours() * 3600 * 1000); + String token = AuthUtil.generateToken(authConfig.getSecret(), credentials); + LoginResult loginResult = new LoginResult(); + loginResult.setToken(token); + return ResponseData.create().data(loginResult).success(); + } +} diff --git a/src/main/java/com/xuxd/kafka/console/utils/AuthUtil.java b/src/main/java/com/xuxd/kafka/console/utils/AuthUtil.java new file mode 100644 index 0000000..dd5d745 --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/utils/AuthUtil.java @@ -0,0 +1,54 @@ +package com.xuxd.kafka.console.utils; + +import com.google.gson.Gson; +import com.xuxd.kafka.console.beans.Credentials; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.Base64Utils; + +import java.nio.charset.StandardCharsets; + +/** + * @author: xuxd + * @date: 2023/5/14 19:34 + **/ +@Slf4j +public class AuthUtil { + + private static Gson gson = GsonUtil.INSTANCE.get(); + + public static String generateToken(String secret, Credentials info) { + String json = gson.toJson(info); + String str = json + secret; + String signature = MD5Util.md5(str); + return Base64Utils.encodeToString(json.getBytes(StandardCharsets.UTF_8)) + "." + + Base64Utils.encodeToString(signature.getBytes(StandardCharsets.UTF_8)); + } + + public static boolean isToken(String token) { + return token.split("\\.").length == 2; + } + + public static Credentials parseToken(String secret, String token) { + if (!isToken(token)) { + return Credentials.INVALID; + } + String[] arr = token.split("\\."); + String infoStr = new String(Base64Utils.decodeFromString(arr[0]), StandardCharsets.UTF_8); + String signature = new String(Base64Utils.decodeFromString(arr[1]), StandardCharsets.UTF_8); + + String encrypt = MD5Util.md5(infoStr + secret); + if (!encrypt.equals(signature)) { + return Credentials.INVALID; + } + try { + Credentials credentials = gson.fromJson(infoStr, Credentials.class); + if (credentials.getExpiration() < System.currentTimeMillis()) { + return Credentials.INVALID; + } + return credentials; + } catch (Exception e) { + log.error("解析token失败: {}", token, e); + return Credentials.INVALID; + } + } +} diff --git a/src/main/java/com/xuxd/kafka/console/utils/MD5Util.java b/src/main/java/com/xuxd/kafka/console/utils/MD5Util.java new file mode 100644 index 0000000..801699f --- /dev/null +++ b/src/main/java/com/xuxd/kafka/console/utils/MD5Util.java @@ -0,0 +1,32 @@ +package com.xuxd.kafka.console.utils; + +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * @author: xuxd + * @date: 2023/5/14 20:25 + **/ +@Slf4j +public class MD5Util { + + public static MessageDigest getInstance() { + try { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + return md5; + } catch (NoSuchAlgorithmException e) { + return null; + } + } + + public static String md5(String str) { + MessageDigest digest = getInstance(); + if (digest == null) { + return null; + } + return new String(digest.digest(str.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 8400628..e372073 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -47,3 +47,9 @@ logging: cron: # clear-dirty-user: 0 * * * * ? clear-dirty-user: 0 0 1 * * ? + +# 权限认证设置,设置为true,需要先登录才能访问 +auth: + enable: true + # 登录用户token的过期时间,单位:小时 + expire-hours: 24 \ No newline at end of file diff --git a/ui/src/App.vue b/ui/src/App.vue index a07c4a0..2d8dde4 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -25,12 +25,12 @@ diff --git a/ui/src/router/index.js b/ui/src/router/index.js index d69f292..789b782 100644 --- a/ui/src/router/index.js +++ b/ui/src/router/index.js @@ -1,6 +1,7 @@ import Vue from "vue"; import VueRouter from "vue-router"; import Home from "../views/Home.vue"; +import Store from "@/store"; Vue.use(VueRouter); @@ -53,13 +54,21 @@ const routes = [ path: "/client-quota-page", name: "ClientQuota", component: () => - import(/* webpackChunkName: "cluster" */ "../views/quota/ClientQuota.vue"), + import( + /* webpackChunkName: "cluster" */ "../views/quota/ClientQuota.vue" + ), }, { path: "/user-page", name: "UserManage", component: () => - import(/* webpackChunkName: "cluster" */ "../views/user/UserManage.vue"), + import(/* webpackChunkName: "cluster" */ "../views/user/UserManage.vue"), + }, + { + path: "/login-page", + name: "Login", + component: () => + import(/* webpackChunkName: "cluster" */ "../views/login/Login.vue"), }, ]; @@ -70,4 +79,49 @@ const router = new VueRouter({ routes, }); +router.beforeEach((to, from, next) => { + const enableAuth = Store.state.auth.enable; + if (!enableAuth) { + next(); + } else { + if (to.path === "/login-page") { + next(); + } else { + let token = localStorage.getItem("access_token"); + if (token === null || token === "") { + next("/login-page"); + } else { + next(); + } + } + } +}); + +let originPush = VueRouter.prototype.push; +let originReplace = VueRouter.prototype.replace; +VueRouter.prototype.push = function (location, resolve, reject) { + if (resolve && reject) { + originPush.call(this, location, resolve, reject); + } else { + originPush.call( + this, + location, + () => {}, + () => {} + ); + } +}; +VueRouter.prototype.replace = function (location, resolve, reject) { + if (resolve && reject) { + originReplace.call(this, location, resolve, reject); + } else { + originReplace.call( + this, + location, + () => {}, + () => {} + ); + } +}; + export default router; diff --git a/ui/src/store/index.js b/ui/src/store/index.js index 78d8c4a..9ef4040 100644 --- a/ui/src/store/index.js +++ b/ui/src/store/index.js @@ -1,6 +1,6 @@ import Vue from "vue"; import Vuex from "vuex"; -import { CLUSTER } from "@/store/mutation-types"; +import { CLUSTER, AUTH } from "@/store/mutation-types"; import { setClusterInfo } from "@/utils/local-cache"; Vue.use(Vuex); @@ -12,6 +12,9 @@ export default new Vuex.Store({ clusterName: undefined, enableSasl: false, }, + auth: { + enable: false, + }, }, mutations: { [CLUSTER.SWITCH](state, clusterInfo) { @@ -28,6 +31,12 @@ export default new Vuex.Store({ state.clusterInfo.enableSasl = enableSasl; setClusterInfo(clusterInfo); }, + [AUTH.ENABLE](state, enable) { + state.auth.enable = enable; + }, + [AUTH.SET](state, info) { + localStorage.setItem("access_token", info); + }, }, actions: {}, modules: {}, diff --git a/ui/src/store/mutation-types.js b/ui/src/store/mutation-types.js index f5ec573..227a790 100644 --- a/ui/src/store/mutation-types.js +++ b/ui/src/store/mutation-types.js @@ -1,3 +1,8 @@ export const CLUSTER = { SWITCH: "switchCluster", }; + +export const AUTH = { + ENABLE: "enable", + SET: "setToken", +}; diff --git a/ui/src/utils/api.js b/ui/src/utils/api.js index b098723..27549b7 100644 --- a/ui/src/utils/api.js +++ b/ui/src/utils/api.js @@ -346,4 +346,15 @@ export const UserManageApi = { url: "/sys/user/manage/user/password", method: "post", }, +}; + +export const AuthApi = { + enable: { + url: "/auth/enable", + method: "get", + }, + login: { + url: "/auth/login", + method: "post", + }, }; \ No newline at end of file diff --git a/ui/src/utils/request.js b/ui/src/utils/request.js index 119e8d8..8bf2a3d 100644 --- a/ui/src/utils/request.js +++ b/ui/src/utils/request.js @@ -2,7 +2,7 @@ import axios from "axios"; import notification from "ant-design-vue/es/notification"; import { VueAxios } from "./axios"; import { getClusterInfo } from "@/utils/local-cache"; - +import Router from "@/router"; // 创建 axios 实例 const request = axios.create({ // API 请求的默认前缀 @@ -10,14 +10,24 @@ const request = axios.create({ timeout: 120000, // 请求超时时间 }); +// axios.defaults.headers.common['X-Auth-Token'] = localStorage.getItem('access_token'); + // 异常拦截处理器 const errorHandler = (error) => { if (error.response) { - const data = error.response.data; - notification.error({ - message: error.response.status, - description: JSON.stringify(data), - }); + if (error.response.status == 401) { + notification.error({ + message: error.response.status, + description: "请登录", + }); + Router.push({ path: "/login-page" }); + } else { + const data = error.response.data; + notification.error({ + message: error.response.status, + description: JSON.stringify(data), + }); + } } return Promise.reject(error); }; @@ -29,6 +39,10 @@ request.interceptors.request.use((config) => { config.headers["X-Cluster-Info-Id"] = clusterInfo.id; // config.headers["X-Cluster-Info-Name"] = encodeURIComponent(clusterInfo.clusterName); } + const token = localStorage.getItem('access_token') + if (token) { + config.headers["X-Auth-Token"] = token; + } return config; }, errorHandler); diff --git a/ui/src/views/login/Login.vue b/ui/src/views/login/Login.vue new file mode 100644 index 0000000..1e3eb63 --- /dev/null +++ b/ui/src/views/login/Login.vue @@ -0,0 +1,103 @@ + + + + + From 238507de19643a03fd6338bc40df5d324b7078dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=99=93=E4=B8=9C?= <763795151@qq.com> Date: Mon, 15 May 2023 21:58:55 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=E6=9D=83=E9=99=90=E9=85=8D=E7=BD=AE.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 2 +- src/main/resources/db/data-h2.sql | 69 +++++++++++++++++++++++++++++- ui/src/App.vue | 36 ++++++++++++++-- ui/src/directives/action.js | 13 ++++++ ui/src/main.js | 1 + ui/src/store/index.js | 11 +++-- ui/src/store/mutation-types.js | 3 +- ui/src/utils/constants.js | 4 ++ ui/src/utils/local-cache.js | 32 ++++++++++++++ ui/src/views/Home.vue | 2 +- ui/src/views/login/Login.vue | 4 +- ui/src/views/topic/Topic.vue | 3 +- ui/src/views/user/Role.vue | 12 ++++++ 13 files changed, 180 insertions(+), 12 deletions(-) create mode 100644 ui/src/directives/action.js diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e372073..304feee 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -50,6 +50,6 @@ cron: # 权限认证设置,设置为true,需要先登录才能访问 auth: - enable: true + enable: false # 登录用户token的过期时间,单位:小时 expire-hours: 24 \ No newline at end of file diff --git a/src/main/resources/db/data-h2.sql b/src/main/resources/db/data-h2.sql index a9a1360..775b1be 100644 --- a/src/main/resources/db/data-h2.sql +++ b/src/main/resources/db/data-h2.sql @@ -2,4 +2,71 @@ -- -- INSERT INTO t_kafka_user (id, username, password) VALUES -- (1, 'Jone', 'p1'), --- (2, 'Jack', 'p2'); \ No newline at end of file +-- (2, 'Jack', 'p2'); + +insert into t_sys_permission(id, name,type,parent_id,permission) values(0,'主页',0,null,'home'); + +insert into t_sys_permission(id, name,type,parent_id,permission) values(10,'集群',0,null,'cluster'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(11,'集群信息',1,10,'cluster'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(12,'属性配置',1,11,'cluster:property-config'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(13,'日志配置',1,11,'cluster:log-config'); + +insert into t_sys_permission(id, name,type,parent_id,permission) values(20,'Topic',0,null,'topic'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(21,'topic',1,20,'topic'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(22,'刷新',1,21,'topic:load'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(23,'新增',1,21,'topic:add'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(24,'批量删除',1,21,'topic:batch-del'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(25,'删除',1,21,'topic:del'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(26,'分区详情',1,21,'topic:partition-detail'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(27,'首选副本作leader',1,26,'topic:partition-detail:preferred'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(28,'增加分区',1,21,'topic:partition-add'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(29,'消费详情',1,21,'topic:consumer-detail'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(30,'属性配置',1,21,'topic:property-config'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(31,'变更副本',1,21,'topic:replication-modify'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(32,'发送统计',1,21,'topic:send-count'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(33,'限流',1,21,'topic:replication-sync-throttle'); + +insert into t_sys_permission(id, name,type,parent_id,permission) values(40,'消费组',0,null,'group'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(41,'消费组',1,40,'group:load'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(42,'新增订阅',1,41,'group:add'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(43,'删除',1,41,'group:del'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(44,'消费端',1,41,'group:client'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(45,'消费详情',1,41,'group:consumer-detail'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(46,'最小位点',1,45,'group:consumer-detail:min'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(47,'最新位点',1,45,'group:consumer-detail:last'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(48,'时间戳',1,45,'group:consumer-detail:timestamp'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(49,'重置位点',1,45,'group:consumer-detail:any'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(50,'位移分区',1,41,'group:offset-partition'); + + +insert into t_sys_permission(id, name,type,parent_id,permission) values(60,'消息',0,null,'message'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(61,'消息',1,60,'message'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(62,'根据时间查询',1,61,'message:search-time'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(63,'根据偏移查询',1,61,'message:search-offset'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(64,'在线发送',1,61,'message:send'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(65,'在线删除',1,61,'message:del'); + +insert into t_sys_permission(id, name,type,parent_id,permission) values(80,'限流',0,null,'quota'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(81,'用户',1,80,'quota:user'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(82,'新增配置',1,81,'quota:user:add'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(83,'客户端ID',1,80,'quota:client'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(84,'新增配置',1,83,'quota:client:add'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(85,'用户和客户端ID',1,80,'quota:user-client'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(86,'新增配置',1,85,'quota:user-client:add'); + + +insert into t_sys_permission(id, name,type,parent_id,permission) values(100,'Acl',0,null,'acl'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(101,'资源授权',1,100,'acl:authority'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(102,'新增权限',1,101,'acl:authority:add'); + +insert into t_sys_permission(id, name,type,parent_id,permission) values(120,'用户',0,null,'user-manage'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(121,'用户列表',1,120,'user-manage:user'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(122,'新增',1,121,'user-manage:user:add'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(123,'删除',1,121,'user-manage:user:del'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(124,'重置密码',1,121,'user-manage:user:reset-pass'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(125,'分配角色',1,121,'user-manage:user:change-role'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(126,'角色列表',1,120,'user-manage:role'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(127,'保存',1,126,'user-manage:role:save'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(128,'删除',1,126,'user-manage:role:del'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(129,'权限列表',1,120,'user-manage:permission'); +insert into t_sys_permission(id, name,type,parent_id,permission) values(130,'个人设置',1,120,'user-manage:setting'); diff --git a/ui/src/App.vue b/ui/src/App.vue index 2d8dde4..1516803 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -19,7 +19,23 @@ >用户 |运维 - 集群:{{ clusterName }} +
+ 集群:{{ clusterName }} + + + | + {{ username }} + + + + + + 退出 + + + + +
@@ -28,9 +44,9 @@ import { KafkaClusterApi, AuthApi } from "@/utils/api"; import request from "@/utils/request"; import { mapMutations, mapState } from "vuex"; -import { getClusterInfo } from "@/utils/local-cache"; +import {deleteToken, deleteUsername, getClusterInfo, getUsername} from "@/utils/local-cache"; import notification from "ant-design-vue/lib/notification"; -import {AUTH, CLUSTER} from "@/store/mutation-types"; +import { AUTH, CLUSTER } from "@/store/mutation-types"; export default { data() { @@ -46,13 +62,19 @@ export default { ...mapState({ clusterName: (state) => state.clusterInfo.clusterName, enableSasl: (state) => state.clusterInfo.enableSasl, + showUsername: (state) => state.auth.enable && state.auth.username, + username: (state) => state.auth.username, }), }, methods: { ...mapMutations({ switchCluster: CLUSTER.SWITCH, enableAuth: AUTH.ENABLE, + setUsername: AUTH.SET_USERNAME, }), + beforeLoadFn() { + this.setUsername(getUsername()); + }, intAuthState() { request({ url: AuthApi.enable.url, @@ -85,6 +107,14 @@ export default { this.switchCluster(clusterInfo); } }, + logout() { + deleteToken(); + deleteUsername(); + this.$router.push("/login-page"); + }, + }, + mounted() { + this.beforeLoadFn(); }, }; diff --git a/ui/src/directives/action.js b/ui/src/directives/action.js new file mode 100644 index 0000000..1131a46 --- /dev/null +++ b/ui/src/directives/action.js @@ -0,0 +1,13 @@ +import Vue from "vue"; + +const action = Vue.directive("action", { + inserted: function (el, binding) { + const actionName = binding.arg; + if (actionName != "action") { + (el.parentNode && el.parentNode.removeChild(el)) || + (el.style.display = "none"); + } + }, +}); + +export default action; diff --git a/ui/src/main.js b/ui/src/main.js index 3f9f7ef..ed24114 100644 --- a/ui/src/main.js +++ b/ui/src/main.js @@ -6,6 +6,7 @@ import store from "./store"; import Antd from "ant-design-vue"; import "ant-design-vue/dist/antd.css"; import { VueAxios } from "./utils/request"; +import "@/directives/action"; Vue.config.productionTip = false; Vue.use(Antd); diff --git a/ui/src/store/index.js b/ui/src/store/index.js index 9ef4040..99595d0 100644 --- a/ui/src/store/index.js +++ b/ui/src/store/index.js @@ -1,7 +1,7 @@ import Vue from "vue"; import Vuex from "vuex"; import { CLUSTER, AUTH } from "@/store/mutation-types"; -import { setClusterInfo } from "@/utils/local-cache"; +import { setClusterInfo, setToken, setUsername } from "@/utils/local-cache"; Vue.use(Vuex); @@ -14,6 +14,7 @@ export default new Vuex.Store({ }, auth: { enable: false, + username: "", }, }, mutations: { @@ -34,8 +35,12 @@ export default new Vuex.Store({ [AUTH.ENABLE](state, enable) { state.auth.enable = enable; }, - [AUTH.SET](state, info) { - localStorage.setItem("access_token", info); + [AUTH.SET_TOKEN](state, info) { + setToken(info); + }, + [AUTH.SET_USERNAME](state, username) { + setUsername(username); + state.auth.username = username; }, }, actions: {}, diff --git a/ui/src/store/mutation-types.js b/ui/src/store/mutation-types.js index 227a790..090b5b9 100644 --- a/ui/src/store/mutation-types.js +++ b/ui/src/store/mutation-types.js @@ -4,5 +4,6 @@ export const CLUSTER = { export const AUTH = { ENABLE: "enable", - SET: "setToken", + SET_TOKEN: "setToken", + SET_USERNAME: "setUsername", }; diff --git a/ui/src/utils/constants.js b/ui/src/utils/constants.js index bd15f7a..c5432b9 100644 --- a/ui/src/utils/constants.js +++ b/ui/src/utils/constants.js @@ -4,4 +4,8 @@ export const ConstantEvent = { export const Cache = { clusterInfo: "clusterInfo", + auth: "auth", + token: "access_token", + username: "login_user", + enableAuth: "enable_auth", }; diff --git a/ui/src/utils/local-cache.js b/ui/src/utils/local-cache.js index 23ebeb9..be8a174 100644 --- a/ui/src/utils/local-cache.js +++ b/ui/src/utils/local-cache.js @@ -8,3 +8,35 @@ export function getClusterInfo() { const str = localStorage.getItem(Cache.clusterInfo); return str ? JSON.parse(str) : undefined; } + +// export function setAuth(auth) { +// localStorage.setItem(Cache.auth, JSON.stringify(auth)); +// } + +export function setToken(token) { + localStorage.setItem(Cache.token, token); +} + +export function getToken() { + return localStorage.getItem(Cache.token); +} + +export function deleteToken() { + localStorage.removeItem(Cache.token); +} + +export function deleteUsername() { + localStorage.removeItem(Cache.username); +} + +export function setUsername(username) { + localStorage.setItem(Cache.username, username); +} + +export function getUsername() { + return localStorage.getItem(Cache.username); +} + +// export function setEnableAuth(enable) { +// localStorage.setItem() +// } diff --git a/ui/src/views/Home.vue b/ui/src/views/Home.vue index 55eac8e..10b43dd 100644 --- a/ui/src/views/Home.vue +++ b/ui/src/views/Home.vue @@ -1,6 +1,6 @@