多租户同步、跨租户部门以及人员同步、多租户登录解决思路

背景: 最近我们接了一个项目,该项目有四个租户,分别是集团总部、公司A、公司B、公司C四个租户,我的工作是同步四个租户的用户到我们的系统。其中涉及到跨租户人员调整,跨租户部门调整,以及多租户登录问题,还是有点难度的。

名词解释

  1. 跨租户人员调整:例如公司A中的某个人被借调到集团总部
  2. 跨租户部门调整:例如公司A中的某个部门整体需要调整到集团总部,包括该部门和部门成员以及所有子部门和所有子部门用户全部调整到集团总部
  3. 多租户登录:例如同一个用户存在在公司A、公司B等多个租户的情况下登录

问题所在

  1. 部门同步同步过来的部门是没有顺序的,有可能子部门先过来,父部门再过来
  2. 如何处理部门跨租户调整时,子部门先过来的情况,此时并没有父部门
  3. 登录需要oauth单点登录

问题解决

部门同步

  1. 构建部门映射表​​:通过遍历原始列表,将部门ID作为键,部门对象作为值存入deptMap,实现O(1)时间复杂度的父部门查找。
  2. 计算部门层级​​:通过getDeptLevel函数递归(实际为循环)计算每个部门的层级:
    ​​根部门​​:层级为0(无父部门)。
    ​​子部门​​:层级为父部门层级+1。
    ​​终止条件​​:父部门不存在时停止计算。
  3. 排序逻辑​​
    排序规则​​:
    1.层级优先​​:层级越低的部门(更靠近根)排在前面。
    2.父部门ID次之​​:同一层级内,父部门ID较小的部门优先。
    3.部门ID最后​​:父部门相同的情况下,按部门ID升序排列。
    ​​数据结构​​:使用SortableDept结构体临时存储部门及其层级、父ID信息,便于排序。
  4. 生成结果​​
    提取排序后的SortableDept列表中的部门对象,返回最终结果。
type DeptIDANDParentID struct {
	DeptID       string `json:"deptId"`
	ParentDeptID string `json:"parentDeptId"`
}
type SortableDept struct {
	Dept     DeptIDANDParentID
	Level    int    // 部门层级,根部门为0
	ParentID string // 父部门ID,用于同层级排序
}
// sortDeptsByParentID 按父部门ID排序,确保相同父ID的部门相邻
func (s *service) sortDeptsByParentID(depts []DeptIDANDParentID) []DeptIDANDParentID {
	// 1. 构建部门ID到部门的映射
	deptMap := make(map[string]DeptIDANDParentID)
	for _, dept := range depts {
		deptMap[dept.DeptID] = dept
	}

	// 2. 计算每个部门的层级并准备排序信息
	var sortableDepts []SortableDept
	for _, dept := range depts {
		level := s.getDeptLevel(dept, deptMap)
		sortableDepts = append(sortableDepts, SortableDept{
			Dept:     dept,
			Level:    level,
			ParentID: dept.ParentDeptID,
		})
	}

	// 3. 排序:先按层级,再按父部门ID,最后按部门ID
	sort.Slice(sortableDepts, func(i, j int) bool {
		// 先比较层级
		if sortableDepts[i].Level != sortableDepts[j].Level {
			return sortableDepts[i].Level < sortableDepts[j].Level
		}
		// 层级相同则比较父部门ID
		if sortableDepts[i].ParentID != sortableDepts[j].ParentID {
			return sortableDepts[i].ParentID < sortableDepts[j].ParentID
		}
		// 父ID也相同则比较部门ID
		return sortableDepts[i].Dept.DeptID < sortableDepts[j].Dept.DeptID
	})

	// 4. 提取排序后的部门列表
	var result []DeptIDANDParentID
	for _, sd := range sortableDepts {
		result = append(result, sd.Dept)
	}
	return result
}

// getDeptLevel 计算部门的层级(根部门为0)
func (s *service) getDeptLevel(dept DeptIDANDParentID, deptMap map[string]DeptIDANDParentID) int {
	level := 0
	current := dept
	for current.ParentDeptID != "" {
		parent, exists := deptMap[current.ParentDeptID]
		if !exists {
			break // 父部门不存在,停止计算
		}
		level++
		current = parent
	}
	return level
}

跨租户部门调整

处理部门在旧租户下的逻辑

  1. 将当前部门ID记到父部门全路径上
  2. 记录租户变更部门的父部门全路径[array]
  3. 记录租户变更部门ID[array]
  4. 查询当前部门全部用户,然后对查询到用户先放到map里面map[deptId]staffInfo,然后做离职处理
  5. 然后停用当前部门

处理部门在新租户的逻辑

  1. 遍历父部门全路径数组
  2. 将父部门全路径分开成单个部门ID
  3. 遍历部门ID,判断当前部门ID有没有在租户变更部门ID列表里
  4. 如果存在,先在新租户下创建新部门
  5. 然后在新部门中创建用户
  6. 如果不在直接跳过循环
  7. 结束

跨租户用户调整

  1. 对当前用户做离职处理
  2. 然后在新租户下创建新的用户

多租户用户登录

  1. 在oauth_back回调接口时,判断是不是多租户
  2. 如果不是多租户直接登录
  3. 如果是多租户,将租户信息存入redis,然后将key添加在我们系统登录页面的url上
  4. 跳转到我们系统的登录页面
  5. 前端根据key请求接口获取租户信息,显示在页面上
  6. 用户选择需要登录的租户进行登录
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

终生成长者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值