package tech.powerjob.server.auth.service.permission; import com.google.common.collect.*; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import tech.powerjob.server.auth.Permission; import tech.powerjob.server.auth.Role; import tech.powerjob.server.auth.RoleScope; import tech.powerjob.server.persistence.remote.model.AppInfoDO; import tech.powerjob.server.persistence.remote.model.UserRoleDO; import tech.powerjob.server.persistence.remote.repository.AppInfoRepository; import tech.powerjob.server.persistence.remote.repository.UserRoleRepository; import javax.annotation.Resource; import java.util.*; /** * PowerJobPermissionService * * @author tjq * @since 2024/2/11 */ @Slf4j @Service public class PowerJobPermissionServiceImpl implements PowerJobPermissionService { @Resource private AppInfoRepository appInfoRepository; @Resource private UserRoleRepository userRoleRepository; @Override public boolean hasPermission(Long userId, RoleScope roleScope, Long target, Permission requiredPermission) { final List userRoleList = Optional.ofNullable(userRoleRepository.findAllByUserId(userId)).orElse(Collections.emptyList()); Multimap appId2Role = ArrayListMultimap.create(); Multimap namespaceId2Role = ArrayListMultimap.create(); List globalRoles = Lists.newArrayList(); for (UserRoleDO userRole : userRoleList) { final Role role = Role.of(userRole.getRole()); // 处理全局权限 if (RoleScope.GLOBAL.getV() == userRole.getScope()) { if (Role.ADMIN.equals(role)) { return true; } globalRoles.add(role); } if (RoleScope.NAMESPACE.getV() == userRole.getScope()) { namespaceId2Role.put(userRole.getTarget(), role); } if (RoleScope.APP.getV() == userRole.getScope()) { appId2Role.put(userRole.getTarget(), role); } } // 前置判断需要的权限(新增场景还没有 appId or namespaceId) if (requiredPermission == Permission.NONE) { return true; } // 检验全局穿透权限 for (Role role : globalRoles) { if (role.getPermissions().contains(requiredPermission)) { return true; } } // 无超级管理员权限,校验普通权限 if (RoleScope.APP.equals(roleScope)) { return checkAppPermission(target, requiredPermission, appId2Role, namespaceId2Role); } if (RoleScope.NAMESPACE.equals(roleScope)) { return checkNamespacePermission(target, requiredPermission, namespaceId2Role); } return false; } @Override public void grantRole(RoleScope roleScope, Long target, Long userId, Role role, String extra) { UserRoleDO userRoleDO = new UserRoleDO(); userRoleDO.setGmtCreate(new Date()); userRoleDO.setGmtModified(new Date()); userRoleDO.setExtra(extra); userRoleDO.setScope(roleScope.getV()); userRoleDO.setTarget(target); userRoleDO.setUserId(userId); userRoleDO.setRole(role.getV()); userRoleRepository.saveAndFlush(userRoleDO); log.info("[PowerJobPermissionService] [grantPermission] saveAndFlush userRole successfully: {}", userRoleDO); } @Override public void retrieveRole(RoleScope roleScope, Long target, Long userId, Role role) { List originUserRole = userRoleRepository.findAllByScopeAndTargetAndRoleAndUserId(roleScope.getV(), target, role.getV(), userId); log.info("[PowerJobPermissionService] [retrievePermission] origin rule: {}", originUserRole); Optional.ofNullable(originUserRole).orElse(Collections.emptyList()).forEach(r -> { userRoleRepository.deleteById(r.getId()); log.info("[PowerJobPermissionService] [retrievePermission] delete UserRole: {}", r); }); } @Override public Map> fetchUserWithPermissions(RoleScope roleScope, Long target) { List permissionUserList = userRoleRepository.findAllByScopeAndTarget(roleScope.getV(), target); Map> ret = Maps.newHashMap(); Optional.ofNullable(permissionUserList).orElse(Collections.emptyList()).forEach(userRoleDO -> { Role role = Role.of(userRoleDO.getRole()); Set userIds = ret.computeIfAbsent(role, ignore -> Sets.newHashSet()); userIds.add(userRoleDO.getUserId()); }); return ret; } @Override public Map> fetchUserHadPermissionTargets(RoleScope roleScope, Long userId) { Map> ret = Maps.newHashMap(); List userRoleDOList = userRoleRepository.findAllByUserIdAndScope(userId, roleScope.getV()); Optional.ofNullable(userRoleDOList).orElse(Collections.emptyList()).forEach(r -> { Role role = Role.of(r.getRole()); List targetIds = ret.computeIfAbsent(role, ignore -> Lists.newArrayList()); targetIds.add(r.getTarget()); }); return ret; } private boolean checkAppPermission(Long targetId, Permission requiredPermission, Multimap appId2Role, Multimap namespaceId2Role) { final Collection appRoles = appId2Role.get(targetId); for (Role role : appRoles) { if (role.getPermissions().contains(requiredPermission)) { return true; } } // 校验 namespace 穿透权限 Optional appInfoOpt = appInfoRepository.findById(targetId); if (!appInfoOpt.isPresent()) { throw new IllegalArgumentException("can't find appInfo by appId in permission check: " + targetId); } Long namespaceId = Optional.ofNullable(appInfoOpt.get().getNamespaceId()).orElse(-1L); Collection namespaceRoles = namespaceId2Role.get(namespaceId); for (Role role : namespaceRoles) { if (role.getPermissions().contains(requiredPermission)) { return true; } } return false; } private boolean checkNamespacePermission(Long targetId, Permission requiredPermission, Multimap namespaceId2Role) { Collection namespaceRoles = namespaceId2Role.get(targetId); for (Role role : namespaceRoles) { if (role.getPermissions().contains(requiredPermission)) { return true; } } return false; } }