Skip to content

Commit

Permalink
feat:用户个人视角 权限管理优化 TencentBlueKing#11138
Browse files Browse the repository at this point in the history
  • Loading branch information
fcfang123 committed Nov 4, 2024
1 parent 3e1b774 commit c8c7d16
Show file tree
Hide file tree
Showing 18 changed files with 361 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,8 @@ enum class JoinedType {
DIRECT,

// 通过模板加入
TEMPLATE
TEMPLATE,

// 通过组织加入
DEPARTMENT
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.tencent.devops.auth.pojo.request

import com.tencent.devops.auth.pojo.ResourceMemberInfo
import com.tencent.devops.auth.pojo.enum.OperateChannel
import io.swagger.v3.oas.annotations.media.Schema

@Schema(title = "用户组成员处理公共请求体")
Expand All @@ -13,12 +14,16 @@ open class GroupMemberCommonConditionReq(
open val allSelection: Boolean = false,
@get:Schema(title = "是否排除唯一管理员组")
open var excludedUniqueManagerGroup: Boolean = false,
@get:Schema(title = "是否排除授权代持人失效相关组")
open var excludeInvalidAuthorizationsForOperateGroups: Boolean = false,
@get:Schema(title = "目标对象")
open val targetMember: ResourceMemberInfo
open val targetMember: ResourceMemberInfo,
@get:Schema(title = "操作渠道")
open val operateChannel: OperateChannel = OperateChannel.MANAGER
) {
override fun toString(): String {
return "GroupMemberCommonConditionReq(groupIds=$groupIds,resourceTypes=$resourceTypes," +
"allSelection=$allSelection,excludedUniqueManagerGroup=$excludedUniqueManagerGroup," +
"targetMember=$targetMember)"
"targetMember=$targetMember,operateChannel=$operateChannel)"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ package com.tencent.devops.auth.pojo.request

import com.tencent.devops.auth.constant.AuthMessageCode.INVALID_HANDOVER_TO
import com.tencent.devops.auth.pojo.ResourceMemberInfo
import com.tencent.devops.auth.pojo.enum.OperateChannel
import com.tencent.devops.common.api.exception.ErrorCodeException
import io.swagger.v3.oas.annotations.media.Schema

Expand All @@ -42,15 +43,21 @@ data class GroupMemberHandoverConditionReq(
override val allSelection: Boolean = false,
@get:Schema(title = "是否排除唯一管理员组")
override var excludedUniqueManagerGroup: Boolean = false,
@get:Schema(title = "是否排除授权代持人失效相关组")
override var excludeInvalidAuthorizationsForOperateGroups: Boolean = false,
@get:Schema(title = "目标对象")
override val targetMember: ResourceMemberInfo,
@get:Schema(title = "操作渠道")
override val operateChannel: OperateChannel = OperateChannel.MANAGER,
@get:Schema(title = "授予人")
val handoverTo: ResourceMemberInfo
) : GroupMemberCommonConditionReq(
groupIds = groupIds,
resourceTypes = resourceTypes,
allSelection = allSelection,
excludedUniqueManagerGroup = excludedUniqueManagerGroup,
excludeInvalidAuthorizationsForOperateGroups = excludeInvalidAuthorizationsForOperateGroups,
operateChannel = operateChannel,
targetMember = targetMember
) {
fun checkHandoverTo() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
package com.tencent.devops.auth.pojo.request

import com.tencent.devops.auth.pojo.ResourceMemberInfo
import com.tencent.devops.auth.pojo.enum.OperateChannel
import io.swagger.v3.oas.annotations.media.Schema

@Schema(title = "用户组成员续期")
Expand All @@ -40,14 +41,20 @@ data class GroupMemberRenewalConditionReq(
override val allSelection: Boolean = false,
@get:Schema(title = "是否排除唯一管理员组")
override var excludedUniqueManagerGroup: Boolean = false,
@get:Schema(title = "是否排除授权代持人失效相关组")
override var excludeInvalidAuthorizationsForOperateGroups: Boolean = false,
@get:Schema(title = "目标对象")
override val targetMember: ResourceMemberInfo,
@get:Schema(title = "操作渠道")
override val operateChannel: OperateChannel = OperateChannel.MANAGER,
@get:Schema(title = "续期时长(天)")
val renewalDuration: Int
) : GroupMemberCommonConditionReq(
groupIds = groupIds,
resourceTypes = resourceTypes,
allSelection = allSelection,
excludedUniqueManagerGroup = excludedUniqueManagerGroup,
excludeInvalidAuthorizationsForOperateGroups = excludeInvalidAuthorizationsForOperateGroups,
operateChannel = operateChannel,
targetMember = targetMember
)
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,7 @@ data class GroupDetailsInfoVo(
@get:Schema(title = "加入方式")
val joinedType: JoinedType,
@get:Schema(title = "操作人")
val operator: String
val operator: String,
@get:Schema(title = "交接/移除用户组中成员导致失效的流水线代持人数量")
val invalidAuthorizationsForOperateGroup: Int = 0
)
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ class AuthAuthorizationDao {
if (resourceName != null) {
conditions.add(RESOURCE_NAME.like("%$resourceName%"))
}
if (!filterResourceCodes.isNullOrEmpty()) {
conditions.add(RESOURCE_CODE.`in`(filterResourceCodes))
}
if (!excludeResourceCodes.isNullOrEmpty()) {
conditions.add(RESOURCE_CODE.notIn(excludeResourceCodes))
}
if (handoverFrom != null) {
conditions.add(HANDOVER_FROM.eq(handoverFrom))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,23 @@ class AuthResourceGroupDao {
}
}

fun listByGroupCode(
dslContext: DSLContext,
projectCode: String,
resourceTypes: List<String>,
iamGroupIds: List<String>,
groupCode: String
): List<AuthResourceGroup> {
return with(TAuthResourceGroup.T_AUTH_RESOURCE_GROUP) {
dslContext.selectFrom(this)
.where(PROJECT_CODE.eq(projectCode))
.and(RESOURCE_TYPE.`in`(resourceTypes))
.and(RELATION_ID.`in`(iamGroupIds))
.and(GROUP_CODE.eq(groupCode))
.fetch().map { convert(it) }
}
}

fun listIamGroupIdsByConditions(
dslContext: DSLContext,
projectCode: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,25 @@ class AuthResourceGroupMemberDao {
}
}

fun listByGroupCode(
dslContext: DSLContext,
projectCode: String,
resourceType: String,
memberId: String,
groupCode: String
): List<String> {
return with(TAuthResourceGroupMember.T_AUTH_RESOURCE_GROUP_MEMBER) {
dslContext.select(RESOURCE_CODE)
.from(this)
.where(PROJECT_CODE.eq(projectCode))
.and(RESOURCE_TYPE.eq(resourceType))
.and(MEMBER_ID.eq(memberId))
.and(GROUP_CODE.eq(groupCode))
.fetch()
.map { it.value1() }
}
}

fun listProjectMembersByComplexConditions(
dslContext: DSLContext,
conditionDTO: ProjectMembersQueryConditionDTO
Expand Down Expand Up @@ -536,7 +555,8 @@ class AuthResourceGroupMemberDao {
resourceType: String? = null,
iamGroupIds: List<Int>? = null,
minExpiredAt: LocalDateTime? = null,
maxExpiredAt: LocalDateTime? = null
maxExpiredAt: LocalDateTime? = null,
memberDeptInfos: List<String>? = null
): Map<String, Long> {
val conditions = buildMemberGroupCondition(
projectCode = projectCode,
Expand All @@ -545,7 +565,8 @@ class AuthResourceGroupMemberDao {
resourceType = resourceType,
iamGroupIds = iamGroupIds,
minExpiredAt = minExpiredAt,
maxExpiredAt = maxExpiredAt
maxExpiredAt = maxExpiredAt,
memberDeptInfos = memberDeptInfos
)
return with(TAuthResourceGroupMember.T_AUTH_RESOURCE_GROUP_MEMBER) {
val select = dslContext.select(RESOURCE_TYPE, count())
Expand Down Expand Up @@ -586,6 +607,7 @@ class AuthResourceGroupMemberDao {
iamGroupIds: List<Int>? = null,
minExpiredAt: LocalDateTime? = null,
maxExpiredAt: LocalDateTime? = null,
memberDeptInfos: List<String>? = null,
offset: Int? = null,
limit: Int? = null
): List<AuthResourceGroupMember> {
Expand All @@ -596,7 +618,8 @@ class AuthResourceGroupMemberDao {
resourceType = resourceType,
iamGroupIds = iamGroupIds,
minExpiredAt = minExpiredAt,
maxExpiredAt = maxExpiredAt
maxExpiredAt = maxExpiredAt,
memberDeptInfos = memberDeptInfos
)
return with(TAuthResourceGroupMember.T_AUTH_RESOURCE_GROUP_MEMBER) {
dslContext.selectFrom(this)
Expand All @@ -615,7 +638,8 @@ class AuthResourceGroupMemberDao {
resourceType: String? = null,
iamGroupIds: List<Int>? = null,
minExpiredAt: LocalDateTime? = null,
maxExpiredAt: LocalDateTime? = null
maxExpiredAt: LocalDateTime? = null,
memberDeptInfos: List<String>? = null
): MutableList<Condition> {
val conditions = mutableListOf<Condition>()
with(TAuthResourceGroupMember.T_AUTH_RESOURCE_GROUP_MEMBER) {
Expand All @@ -633,6 +657,10 @@ class AuthResourceGroupMemberDao {
MEMBER_ID.`in`(iamTemplateIds)
.and(MEMBER_TYPE.eq(ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE)))
)
.or(
MEMBER_ID.`in`(memberDeptInfos)
.and(MEMBER_TYPE.eq(ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT)))
)
)
resourceType?.let { conditions.add(RESOURCE_TYPE.eq(resourceType)) }
minExpiredAt?.let { conditions.add(EXPIRED_TIME.ge(minExpiredAt)) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ import com.tencent.devops.auth.pojo.ResourceMemberInfo
import com.tencent.devops.auth.pojo.dto.IamGroupIdsQueryConditionDTO
import com.tencent.devops.auth.pojo.dto.ProjectMembersQueryConditionDTO
import com.tencent.devops.auth.pojo.enum.JoinedType
import com.tencent.devops.auth.pojo.enum.OperateChannel
import com.tencent.devops.auth.pojo.enum.RemoveMemberButtonControl
import com.tencent.devops.auth.pojo.request.ProjectMembersQueryConditionReq
import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo
import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo
import com.tencent.devops.auth.service.DeptService
import com.tencent.devops.auth.service.PermissionAuthorizationService
import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService
import com.tencent.devops.auth.service.iam.PermissionResourceGroupPermissionService
import com.tencent.devops.auth.service.iam.PermissionResourceGroupService
Expand All @@ -39,7 +41,8 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl(
private val dslContext: DSLContext,
private val deptService: DeptService,
private val iamV2ManagerService: V2ManagerService,
private val rbacCacheService: RbacCacheService
private val rbacCacheService: RbacCacheService,
private val permissionAuthorizationService: PermissionAuthorizationService
) : PermissionResourceGroupAndMemberFacadeService {
override fun getMemberGroupsDetails(
projectId: String,
Expand All @@ -52,6 +55,7 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl(
relatedResourceType: String?,
relatedResourceCode: String?,
action: String?,
operateChannel: OperateChannel?,
start: Int?,
limit: Int?
): SQLPage<GroupDetailsInfoVo> {
Expand All @@ -66,14 +70,15 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl(
action = action
)
)
// 查询成员所在资源用户组列表,直接加入+通过用户组(模板)加入
// 查询成员所在资源用户组列表
val (count, resourceGroupMembers) = permissionResourceMemberService.listResourceGroupMembers(
projectCode = projectId,
memberId = memberId,
resourceType = resourceType,
iamGroupIds = iamGroupIdsByConditions,
minExpiredAt = minExpiredAt,
maxExpiredAt = maxExpiredAt,
operateChannel = operateChannel,
start = start,
limit = limit
)
Expand All @@ -94,6 +99,14 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl(
memberId = memberId,
resourceGroupMembers = resourceGroupMembers
)
// 将用户移出项目管理员/流水线拥有者组后,导致流水线代持人权限失效的数量
val invalidAuthorizationsForOperateGroups =
permissionAuthorizationService.getInvalidAuthorizationsForOperateGroups(
projectCode = projectId,
iamGroupIds = resourceGroupMembers.map { it.iamGroupId },
memberId = memberId
)

val records = mutableListOf<GroupDetailsInfoVo>()
resourceGroupMembers.forEach {
val resourceGroup = resourceGroupMap[it.iamGroupId.toString()]!!
Expand All @@ -103,7 +116,8 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl(
resourceGroup = resourceGroup,
groupMemberDetail = groupMemberDetail,
uniqueManagerGroups = uniqueManagerGroups,
authResourceGroupMember = it
authResourceGroupMember = it,
invalidAuthorizationsForOperateGroups = invalidAuthorizationsForOperateGroups
)
)
}
Expand Down Expand Up @@ -166,7 +180,8 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl(
resourceGroup: TAuthResourceGroupRecord,
groupMemberDetail: MemberGroupDetailsResponse?,
uniqueManagerGroups: List<Int>,
authResourceGroupMember: AuthResourceGroupMember
authResourceGroupMember: AuthResourceGroupMember,
invalidAuthorizationsForOperateGroups: Map<Int, Int>
): GroupDetailsInfoVo {
// 如果用户离职,查询权限中心接口会报错,因此从数据库直接取数据,而不去调用权限中心接口。
val (expiredAt, joinedTime) = if (groupMemberDetail != null) {
Expand All @@ -181,11 +196,12 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl(
)
}
val between = expiredAt - System.currentTimeMillis()
val iamGroupId = resourceGroup.relationId.toInt()
return GroupDetailsInfoVo(
resourceCode = resourceGroup.resourceCode,
resourceName = resourceGroup.resourceName,
resourceType = resourceGroup.resourceType,
groupId = resourceGroup.relationId.toInt(),
groupId = iamGroupId,
groupName = resourceGroup.groupName,
groupDesc = resourceGroup.description,
expiredAtDisplay = when {
Expand Down Expand Up @@ -219,9 +235,11 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl(
},
joinedType = when (authResourceGroupMember.memberType) {
ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE) -> JoinedType.TEMPLATE
ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT) -> JoinedType.DEPARTMENT
else -> JoinedType.DIRECT
},
operator = ""
operator = "",
invalidAuthorizationsForOperateGroup = invalidAuthorizationsForOperateGroups[iamGroupId] ?: 0
)
}

Expand All @@ -233,7 +251,8 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl(
maxExpiredAt: Long?,
relatedResourceType: String?,
relatedResourceCode: String?,
action: String?
action: String?,
operateChannel: OperateChannel?
): List<MemberGroupCountWithPermissionsVo> {
// 查询项目下包含该成员的组列表
val projectGroupIds = authResourceGroupMemberDao.listResourceGroupMember(
Expand All @@ -249,6 +268,16 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl(
iamGroupIds = projectGroupIds
).filter { it.iamTemplateId != null }
.map { it.iamTemplateId.toString() }
// 获取用户部门信息
val memberDeptInfos = if (operateChannel == OperateChannel.PERSONAL) {
deptService.getUserInfo(
userId = "admin",
name = memberId
)?.deptInfo ?: return emptyList()
deptService.getUserDeptInfo(memberId).toList()
} else {
emptyList()
}

val iamGroupIdsByConditions = listIamGroupIdsByConditions(
condition = IamGroupIdsQueryConditionDTO(
Expand All @@ -259,15 +288,16 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl(
action = action
)
)
// 获取成员直接加入的组和通过模板加入的组
// 获取成员加入的用户组
val memberGroupCountMap = authResourceGroupMemberDao.countMemberGroup(
dslContext = dslContext,
projectCode = projectCode,
memberId = memberId,
iamTemplateIds = iamTemplateId,
iamGroupIds = iamGroupIdsByConditions,
minExpiredAt = minExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) },
maxExpiredAt = maxExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) }
maxExpiredAt = maxExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) },
memberDeptInfos = memberDeptInfos
)
val memberGroupCountList = mutableListOf<MemberGroupCountWithPermissionsVo>()
// 项目排在第一位
Expand Down
Loading

0 comments on commit c8c7d16

Please sign in to comment.