This is an automated email from the ASF dual-hosted git repository.

dockerzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/inlong.git


The following commit(s) were added to refs/heads/master by this push:
     new fe41a33d7 [INLONG-8118][Manager] Support tenant user permission 
control (#8119)
fe41a33d7 is described below

commit fe41a33d7a3e6d4657dee55831b619dd298652cd
Author: vernedeng <[email protected]>
AuthorDate: Thu Jun 1 11:39:45 2023 +0800

    [INLONG-8118][Manager] Support tenant user permission control (#8119)
---
 .../inlong/manager/common/enums/ErrorCodeEnum.java |   2 +
 .../manager/common/enums/InlongUserTypeEnum.java   |  76 ++++++++++++++
 ...erRoleEntity.java => TenantUserRoleEntity.java} |   6 +-
 .../dao/mapper/InlongTenantEntityMapper.java       |   2 +-
 ...Mapper.java => TenantUserRoleEntityMapper.java} |  16 +--
 ...tyMapper.xml => TenantUserRoleEntityMapper.xml} |  46 ++++++---
 .../manager/pojo/tenant/InlongTenantInfo.java      |   2 -
 .../manager/pojo/tenant/InlongTenantRequest.java   |   2 -
 .../TenantRoleInfo.java}                           |  26 +++--
 .../manager/pojo/user/TenantRolePageRequest.java}  |  33 +++---
 .../manager/pojo/user/TenantRoleRequest.java}      |  40 +++++---
 .../manager/service/core/impl/RoleServiceImpl.java |  49 ---------
 .../TenantRoleService.java}                        |  34 +++++--
 .../service/user/TenantRoleServiceImpl.java        | 105 +++++++++++++++++++
 .../service/user/TenantRoleServiceTest.java        | 112 +++++++++++++++++++++
 .../main/resources/h2/apache_inlong_manager.sql    |  60 ++++++-----
 .../manager-web/sql/apache_inlong_manager.sql      |  11 +-
 inlong-manager/manager-web/sql/changes-1.8.0.sql   |  14 ++-
 .../web/controller/InlongTenantRoleController.java |  83 +++++++++++++++
 19 files changed, 557 insertions(+), 162 deletions(-)

diff --git 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/ErrorCodeEnum.java
 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/ErrorCodeEnum.java
index b9cb50f8c..289ddba60 100644
--- 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/ErrorCodeEnum.java
+++ 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/ErrorCodeEnum.java
@@ -148,6 +148,8 @@ public enum ErrorCodeEnum {
     CONSUME_PERMISSION_DENIED(3005, "No permission to access this inlong 
consume"),
 
     AUDIT_ID_TYPE_NOT_SUPPORTED(4001, "Audit id type '%s' not supported"),
+
+    TENANT_NOT_EXIST(5001, "Tenant '%s' is not exist"),
     ;
 
     private final int code;
diff --git 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/InlongUserTypeEnum.java
 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/InlongUserTypeEnum.java
new file mode 100644
index 000000000..f5a8fde72
--- /dev/null
+++ 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/InlongUserTypeEnum.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.common.enums;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public enum InlongUserTypeEnum implements IntListValuable {
+
+    /**
+     * Has all privilege
+     */
+    INLONG_ADMIN(0),
+    /**
+     * No privilege to manage the system
+     */
+    INLONG_OPERATOR(1),
+    ;
+
+    @Getter
+    @JsonValue
+    private final Integer code;
+
+    InlongUserTypeEnum(Integer code) {
+        this.code = code;
+    }
+
+    private static final List<Integer> TYPE_CODE_LIST = Arrays.stream(values())
+            .map(InlongUserTypeEnum::getCode)
+            .collect(Collectors.toList());
+
+    public static InlongUserTypeEnum parseCode(Integer value) {
+        return Arrays.stream(InlongUserTypeEnum.class.getEnumConstants())
+                .filter(x -> x.getCode().equals(value))
+                .findAny()
+                .orElse(null);
+    }
+
+    public static Integer parseName(String value) {
+        for (InlongUserTypeEnum type : InlongUserTypeEnum.values()) {
+            if (type.name().equals(value)) {
+                return type.code;
+            }
+        }
+
+        return null;
+    }
+
+    public static String name(Integer value) {
+        return parseCode(value).name();
+    }
+
+    @Override
+    public List<Integer> valueList() {
+        return TYPE_CODE_LIST;
+    }
+}
diff --git 
a/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/UserRoleEntity.java
 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/TenantUserRoleEntity.java
similarity index 89%
copy from 
inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/UserRoleEntity.java
copy to 
inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/TenantUserRoleEntity.java
index 07b3d86cc..ef64b0bab 100644
--- 
a/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/UserRoleEntity.java
+++ 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/TenantUserRoleEntity.java
@@ -23,16 +23,16 @@ import java.io.Serializable;
 import java.util.Date;
 
 /**
- * User role entity, including username, role code, etc.
+ * Tenant User role entity, including username, role code, etc.
  */
 @Data
-public class UserRoleEntity implements Serializable {
+public class TenantUserRoleEntity implements Serializable {
 
     private static final long serialVersionUID = 1L;
     private Integer id;
     private String username;
     private String roleCode;
-
+    private String tenant;
     private Integer disabled;
     private Integer isDeleted;
     private String creator;
diff --git 
a/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/InlongTenantEntityMapper.java
 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/InlongTenantEntityMapper.java
index 86c8a0c4e..dc4fc829f 100644
--- 
a/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/InlongTenantEntityMapper.java
+++ 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/InlongTenantEntityMapper.java
@@ -34,7 +34,7 @@ public interface InlongTenantEntityMapper {
 
     int updateByIdSelective(InlongTenantEntity record);
 
-    Page<InlongTenantEntity> selectByCondition(InlongTenantPageRequest 
pageRequest);
+    Page<InlongTenantEntity> selectByCondition(InlongTenantPageRequest 
request);
 
     InlongTenantEntity selectByName(String name);
 }
\ No newline at end of file
diff --git 
a/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/UserRoleEntityMapper.java
 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/TenantUserRoleEntityMapper.java
similarity index 68%
rename from 
inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/UserRoleEntityMapper.java
rename to 
inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/TenantUserRoleEntityMapper.java
index d941ef0e8..889b2fcf8 100644
--- 
a/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/UserRoleEntityMapper.java
+++ 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/TenantUserRoleEntityMapper.java
@@ -17,22 +17,22 @@
 
 package org.apache.inlong.manager.dao.mapper;
 
-import org.apache.inlong.manager.dao.entity.UserRoleEntity;
+import org.apache.inlong.manager.dao.entity.TenantUserRoleEntity;
+import org.apache.inlong.manager.pojo.user.TenantRolePageRequest;
 
+import com.github.pagehelper.Page;
 import org.springframework.stereotype.Repository;
 
-import java.util.List;
-
 @Repository
-public interface UserRoleEntityMapper {
+public interface TenantUserRoleEntityMapper {
 
-    int insert(UserRoleEntity record);
+    int insert(TenantUserRoleEntity record);
 
-    UserRoleEntity selectById(Integer id);
+    TenantUserRoleEntity selectById(Integer id);
 
-    List<UserRoleEntity> listByUsername(String username);
+    Page<TenantUserRoleEntity> listByCondition(TenantRolePageRequest request);
 
-    int updateById(UserRoleEntity record);
+    int updateById(TenantUserRoleEntity record);
 
     int deleteById(Integer id);
 
diff --git 
a/inlong-manager/manager-dao/src/main/resources/mappers/UserRoleEntityMapper.xml
 
b/inlong-manager/manager-dao/src/main/resources/mappers/TenantUserRoleEntityMapper.xml
similarity index 67%
rename from 
inlong-manager/manager-dao/src/main/resources/mappers/UserRoleEntityMapper.xml
rename to 
inlong-manager/manager-dao/src/main/resources/mappers/TenantUserRoleEntityMapper.xml
index 7408fa352..eb43baa84 100644
--- 
a/inlong-manager/manager-dao/src/main/resources/mappers/UserRoleEntityMapper.xml
+++ 
b/inlong-manager/manager-dao/src/main/resources/mappers/TenantUserRoleEntityMapper.xml
@@ -19,11 +19,12 @@
 -->
 
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd";>
-<mapper namespace="org.apache.inlong.manager.dao.mapper.UserRoleEntityMapper">
-    <resultMap id="BaseResultMap" 
type="org.apache.inlong.manager.dao.entity.UserRoleEntity">
+<mapper 
namespace="org.apache.inlong.manager.dao.mapper.TenantUserRoleEntityMapper">
+    <resultMap id="BaseResultMap" 
type="org.apache.inlong.manager.dao.entity.TenantUserRoleEntity">
         <id column="id" jdbcType="INTEGER" property="id"/>
         <result column="user_name" jdbcType="VARCHAR" property="username"/>
         <result column="role_code" jdbcType="VARCHAR" property="roleCode"/>
+        <result column="tenant" jdbcType="VARCHAR" property="tenant"/>
         <result column="disabled" jdbcType="SMALLINT" property="disabled"/>
         <result column="is_deleted" jdbcType="INTEGER" property="isDeleted"/>
         <result column="creator" jdbcType="VARCHAR" property="creator"/>
@@ -33,32 +34,49 @@
         <result column="version" jdbcType="INTEGER" property="version"/>
     </resultMap>
     <sql id="Base_Column_List">
-        id, user_name, role_code, disabled, is_deleted, creator, modifier, 
create_time, modify_time, version
+        id, user_name, role_code, tenant, disabled, is_deleted, creator, 
modifier, create_time, modify_time, version
     </sql>
 
     <insert id="insert" useGeneratedKeys="true" keyProperty="id"
-            
parameterType="org.apache.inlong.manager.dao.entity.UserRoleEntity">
-        insert into user_role (id, user_name, role_code,
+            
parameterType="org.apache.inlong.manager.dao.entity.TenantUserRoleEntity">
+        insert into tenant_user_role (id, user_name, role_code, tenant,
                                disabled, creator, modifier)
         values (#{id,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, 
#{roleCode,jdbcType=VARCHAR},
-                #{disabled,jdbcType=SMALLINT}, #{creator,jdbcType=VARCHAR}, 
#{modifier,jdbcType=VARCHAR})
+                #{tenant,jdbcType=VARCHAR},#{disabled,jdbcType=SMALLINT},
+                #{creator,jdbcType=VARCHAR}, #{modifier,jdbcType=VARCHAR})
     </insert>
     <select id="selectById" parameterType="java.lang.Integer" 
resultMap="BaseResultMap">
         select
         <include refid="Base_Column_List"/>
-        from user_role
+        from tenant_user_role
         where id = #{id,jdbcType=INTEGER}
     </select>
-    <select id="listByUsername" parameterType="java.lang.String" 
resultMap="BaseResultMap">
-        select
+    <select id="listByCondition"
+            
parameterType="org.apache.inlong.manager.pojo.user.TenantRolePageRequest"
+            resultMap="BaseResultMap">
+      select
         <include refid="Base_Column_List"/>
-        from user_role
-        where user_name = #{username,jdbcType=VARCHAR}
+        from tenant_user_role
+        where is_deleted = 0
+        <if test="username != null and username != ''">
+            and user_name = #{username, jdbcType=VARCHAR}
+        </if>
+        <if test="roleCode != null and roleCode != ''">
+            and role_code = #{roleCode,jdbcType=VARCHAR}
+        </if>
+        <if test="tenant != null and tenant != ''">
+            and tenant = #{tenant, jdbcType=VARCHAR}
+        </if>
+        <if test="disabled != null">
+            and disabled = #{disabled, jdbcType=SMALLINT}
+        </if>
     </select>
 
-    <update id="updateById" 
parameterType="org.apache.inlong.manager.dao.entity.UserRoleEntity">
-        update user_role
+
+    <update id="updateById" 
parameterType="org.apache.inlong.manager.dao.entity.TenantUserRoleEntity">
+        update tenant_user_role
         set user_name  = #{username,jdbcType=VARCHAR},
+            tenant     = #{tenant,jdbcType=VARCHAR},
             role_code  = #{roleCode,jdbcType=VARCHAR},
             disabled   = #{disabled,jdbcType=SMALLINT},
             is_deleted = #{isDeleted,jdbcType=INTEGER},
@@ -70,7 +88,7 @@
 
     <delete id="deleteById" parameterType="java.lang.Integer">
         delete
-        from user_role
+        from tenant_user_role
         where id = #{id,jdbcType=INTEGER}
     </delete>
 </mapper>
diff --git 
a/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/tenant/InlongTenantInfo.java
 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/tenant/InlongTenantInfo.java
index a5cfc8f25..c880e0d77 100644
--- 
a/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/tenant/InlongTenantInfo.java
+++ 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/tenant/InlongTenantInfo.java
@@ -20,7 +20,6 @@ package org.apache.inlong.manager.pojo.tenant;
 import org.apache.inlong.manager.common.util.CommonBeanUtils;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
@@ -35,7 +34,6 @@ import java.util.Date;
 @NoArgsConstructor
 @AllArgsConstructor
 @ApiModel("Inlong tenant info")
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, visible = true, property = "type")
 public class InlongTenantInfo {
 
     @ApiModelProperty(value = "Primary key")
diff --git 
a/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/tenant/InlongTenantRequest.java
 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/tenant/InlongTenantRequest.java
index 2d2e1acdd..78bf34fa7 100644
--- 
a/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/tenant/InlongTenantRequest.java
+++ 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/tenant/InlongTenantRequest.java
@@ -20,7 +20,6 @@ package org.apache.inlong.manager.pojo.tenant;
 import org.apache.inlong.manager.common.validation.UpdateByIdValidation;
 import org.apache.inlong.manager.common.validation.UpdateByKeyValidation;
 
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
@@ -35,7 +34,6 @@ import javax.validation.constraints.Pattern;
 @NoArgsConstructor
 @AllArgsConstructor
 @ApiModel("Tenant request")
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, visible = true, property = "type")
 public class InlongTenantRequest {
 
     @ApiModelProperty(value = "Primary key")
diff --git 
a/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/tenant/InlongTenantInfo.java
 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/user/TenantRoleInfo.java
similarity index 76%
copy from 
inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/tenant/InlongTenantInfo.java
copy to 
inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/user/TenantRoleInfo.java
index a5cfc8f25..4129f6110 100644
--- 
a/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/tenant/InlongTenantInfo.java
+++ 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/user/TenantRoleInfo.java
@@ -15,12 +15,11 @@
  * limitations under the License.
  */
 
-package org.apache.inlong.manager.pojo.tenant;
+package org.apache.inlong.manager.pojo.user;
 
 import org.apache.inlong.manager.common.util.CommonBeanUtils;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
@@ -34,18 +33,23 @@ import java.util.Date;
 @SuperBuilder
 @NoArgsConstructor
 @AllArgsConstructor
-@ApiModel("Inlong tenant info")
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, visible = true, property = "type")
-public class InlongTenantInfo {
+@ApiModel("Inlong tenant user role info")
+public class TenantRoleInfo {
 
     @ApiModelProperty(value = "Primary key")
     private Integer id;
 
-    @ApiModelProperty(value = "Tenant name")
-    private String name;
+    @ApiModelProperty(value = "User name")
+    private String username;
 
-    @ApiModelProperty(value = "Description of the tenant")
-    private String description;
+    @ApiModelProperty(value = "Role code")
+    private String roleCode;
+
+    @ApiModelProperty(value = "Tenant")
+    private String tenant;
+
+    @ApiModelProperty(value = "If disabled")
+    private Integer disabled;
 
     @ApiModelProperty(value = "Name of in creator")
     private String creator;
@@ -62,7 +66,7 @@ public class InlongTenantInfo {
     @ApiModelProperty(value = "Version number")
     private Integer version;
 
-    public InlongTenantRequest genRequest() {
-        return CommonBeanUtils.copyProperties(this, InlongTenantRequest::new);
+    public TenantRoleRequest genRequest() {
+        return CommonBeanUtils.copyProperties(this, TenantRoleRequest::new);
     }
 }
diff --git 
a/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/UserRoleEntity.java
 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/user/TenantRolePageRequest.java
similarity index 60%
copy from 
inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/UserRoleEntity.java
copy to 
inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/user/TenantRolePageRequest.java
index 07b3d86cc..cb980b352 100644
--- 
a/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/UserRoleEntity.java
+++ 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/user/TenantRolePageRequest.java
@@ -15,30 +15,33 @@
  * limitations under the License.
  */
 
-package org.apache.inlong.manager.dao.entity;
+package org.apache.inlong.manager.pojo.user;
 
-import lombok.Data;
+import org.apache.inlong.manager.pojo.common.PageRequest;
 
-import java.io.Serializable;
-import java.util.Date;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
 
-/**
- * User role entity, including username, role code, etc.
- */
 @Data
-public class UserRoleEntity implements Serializable {
+@EqualsAndHashCode(callSuper = false)
+@ApiModel("Tenant user paging query request")
+public class TenantRolePageRequest extends PageRequest {
 
-    private static final long serialVersionUID = 1L;
+    @ApiModelProperty(value = "Primary key")
     private Integer id;
+
+    @ApiModelProperty(value = "User name")
     private String username;
+
+    @ApiModelProperty(value = "Role code")
     private String roleCode;
 
+    @ApiModelProperty(value = "Tenant")
+    private String tenant;
+
+    @ApiModelProperty(value = "If disabled")
     private Integer disabled;
-    private Integer isDeleted;
-    private String creator;
-    private String modifier;
-    private Date createTime;
-    private Date modifyTime;
-    private Integer version;
 
 }
diff --git 
a/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/UserRoleEntity.java
 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/user/TenantRoleRequest.java
similarity index 56%
rename from 
inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/UserRoleEntity.java
rename to 
inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/user/TenantRoleRequest.java
index 07b3d86cc..a65161129 100644
--- 
a/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/UserRoleEntity.java
+++ 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/user/TenantRoleRequest.java
@@ -15,30 +15,40 @@
  * limitations under the License.
  */
 
-package org.apache.inlong.manager.dao.entity;
+package org.apache.inlong.manager.pojo.user;
 
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
-import java.io.Serializable;
-import java.util.Date;
+import javax.validation.constraints.NotBlank;
 
-/**
- * User role entity, including username, role code, etc.
- */
 @Data
-public class UserRoleEntity implements Serializable {
+@NoArgsConstructor
+@AllArgsConstructor
+@ApiModel("Tenant user role request")
+public class TenantRoleRequest {
 
-    private static final long serialVersionUID = 1L;
+    @ApiModelProperty(value = "Primary key")
     private Integer id;
+
+    @ApiModelProperty(value = "User name")
+    @NotBlank
     private String username;
+
+    @ApiModelProperty(value = "Role code")
+    @NotBlank
     private String roleCode;
 
-    private Integer disabled;
-    private Integer isDeleted;
-    private String creator;
-    private String modifier;
-    private Date createTime;
-    private Date modifyTime;
-    private Integer version;
+    @ApiModelProperty(value = "Tenant")
+    @NotBlank
+    private String tenant;
+
+    @ApiModelProperty(value = "If disabled")
+    private Integer disabled = 0;
 
+    @ApiModelProperty(value = "Version number")
+    private Integer version;
 }
diff --git 
a/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/core/impl/RoleServiceImpl.java
 
b/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/core/impl/RoleServiceImpl.java
deleted file mode 100644
index b0b653f17..000000000
--- 
a/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/core/impl/RoleServiceImpl.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.inlong.manager.service.core.impl;
-
-import org.apache.inlong.manager.dao.entity.UserRoleEntity;
-import org.apache.inlong.manager.dao.mapper.UserRoleEntityMapper;
-import org.apache.inlong.manager.service.core.RoleService;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * Role operation
- */
-@Slf4j
-@Service
-public class RoleServiceImpl implements RoleService {
-
-    @Autowired
-    private UserRoleEntityMapper userRoleEntityMapper;
-
-    @Override
-    public List<String> listByUser(String username) {
-        return userRoleEntityMapper.listByUsername(username)
-                .stream()
-                .map(UserRoleEntity::getRoleCode)
-                .collect(Collectors.toList());
-    }
-
-}
diff --git 
a/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/core/RoleService.java
 
b/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/user/TenantRoleService.java
similarity index 52%
rename from 
inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/core/RoleService.java
rename to 
inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/user/TenantRoleService.java
index dce4f5363..f0e1074bb 100644
--- 
a/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/core/RoleService.java
+++ 
b/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/user/TenantRoleService.java
@@ -15,20 +15,36 @@
  * limitations under the License.
  */
 
-package org.apache.inlong.manager.service.core;
+package org.apache.inlong.manager.service.user;
 
-import java.util.List;
+import org.apache.inlong.manager.pojo.user.TenantRoleInfo;
+import org.apache.inlong.manager.pojo.user.TenantRolePageRequest;
+import org.apache.inlong.manager.pojo.user.TenantRoleRequest;
+
+import com.github.pagehelper.PageInfo;
 
 /**
- * Role service
+ * Tenant Role service
  */
-public interface RoleService {
+public interface TenantRoleService {
+
+    /**
+     * List all tenant role by paginating
+     */
+    PageInfo<TenantRoleInfo> listByCondition(TenantRolePageRequest request);
+
+    /**
+     * Save one tenant role
+     */
+    int save(TenantRoleRequest record, String operator);
+
+    /**
+     * Update one tanant role
+     */
+    boolean update(TenantRoleRequest record, String operator);
 
     /**
-     * Get roles based on username
-     *
-     * @param username username
-     * @return Role list
+     * Get one tenant role by id
      */
-    List<String> listByUser(String username);
+    TenantRoleInfo get(int id);
 }
diff --git 
a/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/user/TenantRoleServiceImpl.java
 
b/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/user/TenantRoleServiceImpl.java
new file mode 100644
index 000000000..82ce82cc2
--- /dev/null
+++ 
b/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/user/TenantRoleServiceImpl.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.service.user;
+
+import org.apache.inlong.manager.common.consts.InlongConstants;
+import org.apache.inlong.manager.common.enums.ErrorCodeEnum;
+import org.apache.inlong.manager.common.exceptions.BusinessException;
+import org.apache.inlong.manager.common.util.CommonBeanUtils;
+import org.apache.inlong.manager.common.util.Preconditions;
+import org.apache.inlong.manager.dao.entity.InlongTenantEntity;
+import org.apache.inlong.manager.dao.entity.TenantUserRoleEntity;
+import org.apache.inlong.manager.dao.mapper.InlongTenantEntityMapper;
+import org.apache.inlong.manager.dao.mapper.TenantUserRoleEntityMapper;
+import org.apache.inlong.manager.pojo.user.TenantRoleInfo;
+import org.apache.inlong.manager.pojo.user.TenantRolePageRequest;
+import org.apache.inlong.manager.pojo.user.TenantRoleRequest;
+
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import static 
org.apache.inlong.manager.common.enums.ErrorCodeEnum.TENANT_NOT_EXIST;
+
+/**
+ * Tenant Role operation
+ */
+@Slf4j
+@Service
+public class TenantRoleServiceImpl implements TenantRoleService {
+
+    @Autowired
+    private TenantUserRoleEntityMapper tenantUserRoleEntityMapper;
+
+    @Autowired
+    private InlongTenantEntityMapper tenantMapper;
+
+    @Override
+    public PageInfo<TenantRoleInfo> listByCondition(TenantRolePageRequest 
request) {
+        PageHelper.startPage(request.getPageNum(), request.getPageSize());
+        Page<TenantUserRoleEntity> entityPage = 
tenantUserRoleEntityMapper.listByCondition(request);
+        return entityPage.toPageInfo(entity -> 
CommonBeanUtils.copyProperties(entity, TenantRoleInfo::new));
+    }
+
+    @Override
+    public int save(TenantRoleRequest request, String operator) {
+        String tenantName = request.getTenant();
+        String username = request.getUsername();
+        Preconditions.expectNotBlank(tenantName, "Failed to save tenant user 
role, tenant should not be blank");
+        Preconditions.expectNotBlank(username, "Failed to save tenant user 
role, user should not be blank");
+        Preconditions.expectNotBlank(request.getRoleCode(),
+                "Failed to save tenant user role, role code should not be 
blank");
+
+        InlongTenantEntity tenant = tenantMapper.selectByName(tenantName);
+        Preconditions.expectNotNull(tenant, TENANT_NOT_EXIST, 
String.format(TENANT_NOT_EXIST.getMessage(), tenantName));
+
+        TenantUserRoleEntity entity = CommonBeanUtils.copyProperties(request, 
TenantUserRoleEntity::new);
+        entity.setCreator(operator);
+        entity.setModifier(operator);
+        tenantUserRoleEntityMapper.insert(entity);
+        return entity.getId();
+    }
+
+    @Override
+    public boolean update(TenantRoleRequest request, String operator) {
+        TenantUserRoleEntity exist = 
tenantUserRoleEntityMapper.selectById(request.getId());
+        Preconditions.expectNotNull(exist, ErrorCodeEnum.RECORD_NOT_FOUND,
+                String.format("tenant user role record not found by id=%s", 
request.getId()));
+
+        TenantUserRoleEntity entity = CommonBeanUtils.copyProperties(request, 
TenantUserRoleEntity::new);
+        entity.setModifier(operator);
+        int rowCount = tenantUserRoleEntityMapper.updateById(entity);
+        if (rowCount != InlongConstants.AFFECTED_ONE_ROW) {
+            throw new BusinessException(ErrorCodeEnum.CONFIG_EXPIRED,
+                    String.format(
+                            "failure to update tenant user role with id=%d, 
request version=%d, updated row=%d",
+                            request.getId(), request.getVersion(), rowCount));
+        }
+        return true;
+    }
+
+    @Override
+    public TenantRoleInfo get(int id) {
+        TenantUserRoleEntity entity = 
tenantUserRoleEntityMapper.selectById(id);
+        return CommonBeanUtils.copyProperties(entity, TenantRoleInfo::new);
+    }
+
+}
diff --git 
a/inlong-manager/manager-service/src/test/java/org/apache/inlong/manager/service/user/TenantRoleServiceTest.java
 
b/inlong-manager/manager-service/src/test/java/org/apache/inlong/manager/service/user/TenantRoleServiceTest.java
new file mode 100644
index 000000000..9487868f9
--- /dev/null
+++ 
b/inlong-manager/manager-service/src/test/java/org/apache/inlong/manager/service/user/TenantRoleServiceTest.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.service.user;
+
+import org.apache.inlong.manager.common.exceptions.BusinessException;
+import org.apache.inlong.manager.pojo.user.TenantRoleInfo;
+import org.apache.inlong.manager.pojo.user.TenantRolePageRequest;
+import org.apache.inlong.manager.pojo.user.TenantRoleRequest;
+import org.apache.inlong.manager.pojo.user.UserInfo;
+import org.apache.inlong.manager.pojo.user.UserRoleCode;
+import org.apache.inlong.manager.service.ServiceBaseTest;
+
+import com.github.pagehelper.PageInfo;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import static 
org.apache.inlong.manager.common.enums.ErrorCodeEnum.TENANT_NOT_EXIST;
+
+public class TenantRoleServiceTest extends ServiceBaseTest {
+
+    @Autowired
+    private TenantRoleService service;
+
+    @BeforeAll
+    public static void initUser() {
+        UserInfo userInfo = new UserInfo();
+        userInfo.setName("admin");
+        LoginUserUtils.setUserLoginInfo(userInfo);
+    }
+
+    @Test
+    @Order(1)
+    public void testSaveWithoutTenant() {
+        TenantRoleRequest request = new TenantRoleRequest();
+        request.setTenant("not exist tenant");
+        request.setRoleCode(UserRoleCode.ADMIN);
+        request.setUsername(LoginUserUtils.getLoginUser().getName());
+        int code = -1;
+        try {
+            service.save(request, LoginUserUtils.getLoginUser().getName());
+        } catch (BusinessException e) {
+            code = e.getCode();
+        }
+        Assertions.assertEquals(TENANT_NOT_EXIST.getCode(), code);
+    }
+
+    @Test
+    @Order(2)
+    public void testSaveCorrect() {
+        TenantRoleRequest request = new TenantRoleRequest();
+        request.setTenant("public");
+        request.setUsername(LoginUserUtils.getLoginUser().getName());
+        request.setRoleCode(UserRoleCode.ADMIN);
+        int id = service.save(request, 
LoginUserUtils.getLoginUser().getName());
+        TenantRoleInfo info = service.get(id);
+        Assertions.assertEquals(request.getTenant(), info.getTenant());
+        Assertions.assertEquals(request.getRoleCode(), info.getRoleCode());
+        Assertions.assertEquals(request.getUsername(), info.getUsername());
+    }
+
+    @Test
+    @Order(3)
+    public void testUpdate() {
+        String newUser = "new user";
+        TenantRoleRequest request = new TenantRoleRequest();
+        request.setTenant("public");
+        request.setUsername(newUser);
+        request.setRoleCode(UserRoleCode.ADMIN);
+        int id = service.save(request, 
LoginUserUtils.getLoginUser().getName());
+        TenantRoleInfo oldInfo = service.get(id);
+        oldInfo.setRoleCode(UserRoleCode.OPERATOR);
+        service.update(oldInfo.genRequest(), 
LoginUserUtils.getLoginUser().getName());
+        TenantRoleInfo newInfo = service.get(id);
+        Assertions.assertEquals(UserRoleCode.OPERATOR, newInfo.getRoleCode());
+    }
+
+    @Test
+    @Order(4)
+    public void testList() {
+        int max = 5;
+        TenantRoleRequest request = new TenantRoleRequest();
+        request.setTenant("public");
+        request.setRoleCode(UserRoleCode.OPERATOR);
+        for (int i = 0; i < max; i++) {
+            request.setUsername("testName" + i);
+            service.save(request, LoginUserUtils.getLoginUser().getName());
+        }
+        TenantRolePageRequest pageRequest = new TenantRolePageRequest();
+        pageRequest.setTenant("public");
+        PageInfo<TenantRoleInfo> infos = service.listByCondition(pageRequest);
+        Assertions.assertEquals(max, infos.getSize());
+    }
+
+}
\ No newline at end of file
diff --git 
a/inlong-manager/manager-test/src/main/resources/h2/apache_inlong_manager.sql 
b/inlong-manager/manager-test/src/main/resources/h2/apache_inlong_manager.sql
index e83043c4d..562986fd5 100644
--- 
a/inlong-manager/manager-test/src/main/resources/h2/apache_inlong_manager.sql
+++ 
b/inlong-manager/manager-test/src/main/resources/h2/apache_inlong_manager.sql
@@ -531,19 +531,22 @@ CREATE TABLE IF NOT EXISTS `role`
 -- ----------------------------
 -- Table structure for user_role
 -- ----------------------------
-CREATE TABLE IF NOT EXISTS `user_role`
+CREATE TABLE IF NOT EXISTS `tenant_user_role`
 (
     `id`          int(11)      NOT NULL AUTO_INCREMENT,
     `user_name`   varchar(256) NOT NULL COMMENT 'Username',
     `role_code`   varchar(256) NOT NULL COMMENT 'User role code',
     `disabled`    tinyint(1)   NOT NULL DEFAULT '0' COMMENT 'Whether to 
disabled, 0: enabled, 1: disabled',
+    `tenant`      varchar(256) NOT NULL DEFAULT 'public' COMMENT 'Inlong 
tenant',
     `is_deleted`  int(11)               DEFAULT '0' COMMENT 'Whether to 
delete, 0 is not deleted, if greater than 0, delete',
     `creator`     varchar(256) NOT NULL COMMENT 'Creator name',
     `modifier`    varchar(256)          DEFAULT NULL COMMENT 'Modifier name',
     `create_time` datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 
'Create time',
     `modify_time` datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP COMMENT 'Modify time',
     `version`     int(11)      NOT NULL DEFAULT '1' COMMENT 'Version number, 
which will be incremented by 1 after modification',
-    PRIMARY KEY (`id`)
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `unique_tenant_user` (`user_name`, `tenant`, `is_deleted`),
+    INDEX `index_tenant` (`tenant`, `is_deleted`)
 );
 
 -- ----------------------------
@@ -744,6 +747,31 @@ CREATE TABLE IF NOT EXISTS `stream_heartbeat`
     PRIMARY KEY (`id`),
     UNIQUE KEY `unique_stream_heartbeat` (`component`, `instance`, 
`inlong_group_id`, `inlong_stream_id`)
 );
+
+-- ----------------------------
+-- Table structure for inlong_tenant
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `inlong_tenant`
+(
+    `id`           int(11)      NOT NULL AUTO_INCREMENT,
+    `name`         varchar(256) NOT NULL COMMENT 'Namespace, not support 
modification',
+    `description`  varchar(256) DEFAULT '' COMMENT 'Description of tenant',
+    `is_deleted`   int(11)      DEFAULT '0' COMMENT 'Whether to delete, 0 is 
not deleted, if greater than 0, delete',
+    `creator`      varchar(256) NOT NULL COMMENT 'Creator name',
+    `modifier`     varchar(256) DEFAULT NULL COMMENT 'Modifier name',
+    `create_time`  datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 
'Create time',
+    `modify_time`  datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP COMMENT 'Modify time',
+    `version`      int(11)      NOT NULL DEFAULT '1' COMMENT 'Version number, 
which will be incremented by 1 after modification',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `unique_tenant_key` (`name`, `is_deleted`)
+);
+
+-- ----------------------------
+-- Insert inlong_tenant item
+-- ----------------------------
+INSERT INTO `inlong_tenant`(`name`, `description`, `creator`, `modifier`)
+VALUES ('public', 'Default tenant', 'admin', 'admin');
+
 -- ----------------------------
 -- Table structure for audit_base
 -- ----------------------------
@@ -788,32 +816,10 @@ VALUES ('audit_sdk_collect', 'SDK', 0, '1'),
        ('audit_sort_mysql_input', 'MYSQL', 0, '23'),
        ('audit_sort_mysql_output', 'MYSQL', 1, '24'),
        ('audit_sort_kudu_input', 'KUDU', 0, '25'),
-       ('audit_sort_kudu_output', 'KUDU', 1, '26');
+       ('audit_sort_kudu_output', 'KUDU', 1, '26'),
+       ('audit_sort_postgres_input', 'POSTGRESQL', 0, '27'),
+       ('audit_sort_postgres_output', 'POSTGRESQL', 1, '28');
 
 -- ----------------------------
--- Table structure for inlong_tenant
--- ----------------------------
-CREATE TABLE IF NOT EXISTS `inlong_tenant`
-(
-    `id`           int(11)      NOT NULL AUTO_INCREMENT,
-    `name`         varchar(256) NOT NULL COMMENT 'Namespace, not support 
modification',
-    `description`  varchar(256) DEFAULT '' COMMENT 'Description of tenant',
-    `is_deleted`   int(11)      DEFAULT '0' COMMENT 'Whether to delete, 0 is 
not deleted, if greater than 0, delete',
-    `creator`      varchar(256) NOT NULL COMMENT 'Creator name',
-    `modifier`     varchar(256) DEFAULT NULL COMMENT 'Modifier name',
-    `create_time`  datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 
'Create time',
-    `modify_time`  datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP COMMENT 'Modify time',
-    `version`      int(11)      NOT NULL DEFAULT '1' COMMENT 'Version number, 
which will be incremented by 1 after modification',
-    PRIMARY KEY (`id`),
-    UNIQUE KEY `unique_user_role_key` (`name`, `is_deleted`)
-    ) ENGINE = InnoDB
-    DEFAULT CHARSET = utf8 COMMENT ='Inlong tenant table';
-
--- ----------------------------
--- Insert inlong_tenant item
--- ----------------------------
-INSERT INTO `inlong_tenant`(`name`, `description`, `creator`, `modifier`)
-VALUES ('public', 'Default tenant', 'admin', 'admin');
--- ----------------------------
 
 SET FOREIGN_KEY_CHECKS = 1;
diff --git a/inlong-manager/manager-web/sql/apache_inlong_manager.sql 
b/inlong-manager/manager-web/sql/apache_inlong_manager.sql
index 433c926bf..3573569c3 100644
--- a/inlong-manager/manager-web/sql/apache_inlong_manager.sql
+++ b/inlong-manager/manager-web/sql/apache_inlong_manager.sql
@@ -564,21 +564,24 @@ CREATE TABLE IF NOT EXISTS `role`
 -- ----------------------------
 -- Table structure for user_role
 -- ----------------------------
-CREATE TABLE IF NOT EXISTS `user_role`
+CREATE TABLE IF NOT EXISTS `tenant_user_role`
 (
     `id`          int(11)      NOT NULL AUTO_INCREMENT,
     `user_name`   varchar(256) NOT NULL COMMENT 'Username',
     `role_code`   varchar(256) NOT NULL COMMENT 'User role code',
     `disabled`    tinyint(1)   NOT NULL DEFAULT '0' COMMENT 'Whether to 
disabled, 0: enabled, 1: disabled',
+    `tenant`      varchar(256) NOT NULL DEFAULT 'public' COMMENT 'Inlong 
tenant',
     `is_deleted`  int(11)               DEFAULT '0' COMMENT 'Whether to 
delete, 0 is not deleted, if greater than 0, delete',
     `creator`     varchar(256) NOT NULL COMMENT 'Creator name',
     `modifier`    varchar(256)          DEFAULT NULL COMMENT 'Modifier name',
     `create_time` datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 
'Create time',
     `modify_time` datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP COMMENT 'Modify time',
     `version`     int(11)      NOT NULL DEFAULT '1' COMMENT 'Version number, 
which will be incremented by 1 after modification',
-    PRIMARY KEY (`id`)
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `unique_tenant_user` (`user_name`, `tenant`, `is_deleted`),
+    INDEX `index_tenant` (`tenant`, `is_deleted`)
 ) ENGINE = InnoDB
-  DEFAULT CHARSET = utf8mb4 COMMENT ='User Role Table';
+  DEFAULT CHARSET = utf8mb4 COMMENT ='Tenant User Role Table';
 
 -- ----------------------------
 -- Table structure for workflow_approver
@@ -803,7 +806,7 @@ CREATE TABLE IF NOT EXISTS `inlong_tenant`
     `modify_time`  datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP COMMENT 'Modify time',
     `version`      int(11)      NOT NULL DEFAULT '1' COMMENT 'Version number, 
which will be incremented by 1 after modification',
     PRIMARY KEY (`id`),
-    UNIQUE KEY `unique_user_role_key` (`name`, `is_deleted`)
+    UNIQUE KEY `unique_tenant_key` (`name`, `is_deleted`)
 ) ENGINE = InnoDB
   DEFAULT CHARSET = utf8 COMMENT ='Inlong tenant table';
 
diff --git a/inlong-manager/manager-web/sql/changes-1.8.0.sql 
b/inlong-manager/manager-web/sql/changes-1.8.0.sql
index b3063f876..86e708c20 100644
--- a/inlong-manager/manager-web/sql/changes-1.8.0.sql
+++ b/inlong-manager/manager-web/sql/changes-1.8.0.sql
@@ -39,9 +39,19 @@ CREATE TABLE IF NOT EXISTS `inlong_tenant`
     `modify_time`  datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP COMMENT 'Modify time',
     `version`      int(11)      NOT NULL DEFAULT '1' COMMENT 'Version number, 
which will be incremented by 1 after modification',
     PRIMARY KEY (`id`),
-    UNIQUE KEY `unique_user_role_key` (`tenant`, `is_deleted`)
+    UNIQUE KEY `unique_tenant_key` (`name`, `is_deleted`)
 ) ENGINE = InnoDB
   DEFAULT CHARSET = utf8 COMMENT ='Inlong tenant table';
 
 INSERT INTO `inlong_tenant`(`name`, `description`, `creator`, `modifier`)
-VALUES ('public', 'Default tenant', 'admin', 'admin');
\ No newline at end of file
+VALUES ('public', 'Default tenant', 'inlong_init', 'inlong_init');
+
+-- To support distinguish inlong user permission and tenant permission 
control, please see https://github.com/apache/inlong/issues/8118
+RENAME TABLE user_role TO tenant_user_role;
+ALTER TABLE tenant_user_role
+    ADD tenant VARCHAR(256) DEFAULT 'public' NOT NULL comment 'User tenant';
+ALTER TABLE tenant_user_role
+    ADD CONSTRAINT unique_tenant_user
+        UNIQUE (user_name, tenant, is_deleted);
+CREATE INDEX tenant_user_role
+    ON user_role (tenant);
diff --git 
a/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/controller/InlongTenantRoleController.java
 
b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/controller/InlongTenantRoleController.java
new file mode 100644
index 000000000..c10ccd69b
--- /dev/null
+++ 
b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/controller/InlongTenantRoleController.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.web.controller;
+
+import org.apache.inlong.manager.common.enums.OperationType;
+import org.apache.inlong.manager.pojo.common.Response;
+import org.apache.inlong.manager.pojo.user.TenantRoleInfo;
+import org.apache.inlong.manager.pojo.user.TenantRolePageRequest;
+import org.apache.inlong.manager.pojo.user.TenantRoleRequest;
+import org.apache.inlong.manager.pojo.user.UserRoleCode;
+import org.apache.inlong.manager.service.operationlog.OperationLog;
+import org.apache.inlong.manager.service.user.LoginUserUtils;
+import org.apache.inlong.manager.service.user.TenantRoleService;
+
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.apache.shiro.authz.annotation.RequiresRoles;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api")
+@Api(tags = "Tenant-API")
+public class InlongTenantRoleController {
+
+    @Autowired
+    private TenantRoleService tenantRoleService;
+
+    @RequestMapping(value = "/role/tenant/get/{id}", method = 
RequestMethod.GET)
+    @ApiOperation(value = "Get tenant role")
+    @ApiImplicitParam(name = "id", dataTypeClass = Integer.class, required = 
true)
+    @RequiresRoles(value = UserRoleCode.ADMIN)
+    public Response<TenantRoleInfo> get(@PathVariable int id) {
+        return Response.success(tenantRoleService.get(id));
+    }
+
+    @RequestMapping(value = "/role/tenant/save", method = RequestMethod.POST)
+    @OperationLog(operation = OperationType.CREATE)
+    @ApiOperation(value = "Save tenant role")
+    @RequiresRoles(value = UserRoleCode.ADMIN)
+    public Response<Integer> save(@Validated @RequestBody TenantRoleRequest 
request) {
+        String operator = LoginUserUtils.getLoginUser().getName();
+        return Response.success(tenantRoleService.save(request, operator));
+    }
+
+    @RequestMapping(value = "/role/tenant/update", method = RequestMethod.POST)
+    @OperationLog(operation = OperationType.CREATE)
+    @ApiOperation(value = "Update tenant role")
+    @RequiresRoles(value = UserRoleCode.ADMIN)
+    public Response<Boolean> update(@Validated @RequestBody TenantRoleRequest 
request) {
+        String operator = LoginUserUtils.getLoginUser().getName();
+        return Response.success(tenantRoleService.update(request, operator));
+    }
+
+    @RequestMapping(value = "/role/tenant/list", method = RequestMethod.POST)
+    @ApiOperation(value = "List tenant roles by paginating")
+    public Response<PageInfo<TenantRoleInfo>> listByCondition(@RequestBody 
TenantRolePageRequest request) {
+        return Response.success(tenantRoleService.listByCondition(request));
+    }
+
+}

Reply via email to