package com.imutil.service.impl; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.imutil.entity.CrossTenantAudit; import com.imutil.entity.CrossTenantGrant; import com.imutil.mapper.CrossTenantAuditMapper; import com.imutil.mapper.CrossTenantGrantMapper; import com.imutil.service.CrossTenantService; import lombok.extern.slf4j.Slf4j; import org.noear.solon.annotation.Component; import org.noear.solon.annotation.Inject; import java.time.OffsetDateTime; /** * 跨租户通讯授权服务实现 *
* 授权匹配:正向(from→to) 优先,未命中再查反向双向(to→from 且 direction=1)。
* user 字段 NULL 表示通配;permissions 用 LIKE 匹配是否含 send_msg。
*
* @author imutil
*/
@Slf4j
@Component
public class CrossTenantServiceImpl implements CrossTenantService {
private static final String PERM_SEND_MSG = "send_msg";
@Inject
private CrossTenantGrantMapper grantMapper;
@Inject
private CrossTenantAuditMapper auditMapper;
@Override
public Long checkSendMsgGrant(String fromTenant, String fromUser, String toTenant, String toUser) {
// 同租户或任一租户缺失,不算跨租户通讯
if (fromTenant == null || toTenant == null || fromTenant.equals(toTenant)) {
return null;
}
// 1. 正向授权 from→to
Long gid = matchDirected(fromTenant, fromUser, toTenant, toUser, false);
if (gid != null) {
return gid;
}
// 2. 反向双向授权:记录方向为 to→from 且 direction=1
return matchDirected(toTenant, toUser, fromTenant, fromUser, true);
}
@Override
public void audit(Long grantId, String msgKey, String fromUser, String toUser) {
try {
CrossTenantAudit a = new CrossTenantAudit();
a.setGrantId(grantId);
a.setMsgKey(msgKey);
a.setFromImUserId(fromUser);
a.setToImUserId(toUser);
a.setActionTime(OffsetDateTime.now());
auditMapper.insert(a);
} catch (Exception e) {
// 审计写入失败不阻塞主流程
log.warn("跨租户审计写入失败 grant={} msgKey={} : {}", grantId, msgKey, e.getMessage());
}
}
/**
* 按指定方向匹配一条 send_msg 授权
*
* @param matchFromTenant 查询条件 from_tenant
* @param matchFromUser 查询条件 from_im_user(NULL 通配由 SQL 处理)
* @param matchToTenant 查询条件 to_tenant
* @param matchToUser 查询条件 to_im_user
* @param now 当前时间(校验有效期)
* @param requireBidir 是否要求 direction=1(反向匹配时)
* @return 命中的 grantId,未命中返回 null
*/
private Long matchDirected(String matchFromTenant, String matchFromUser,
String matchToTenant, String matchToUser,
boolean requireBidir) {
CrossTenantGrant g = grantMapper.selectOne(Wrappers.