diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/DriverEnsureProfileDTO.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/DriverEnsureProfileDTO.java index 3844e1b9..cab277e8 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/DriverEnsureProfileDTO.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/DriverEnsureProfileDTO.java @@ -43,7 +43,7 @@ public class DriverEnsureProfileDTO implements Serializable { @Serial private static final long serialVersionUID = 1L; - @Schema(description = "租户ID,为空时取当前登录租户;仍为空则拒绝写库") + @Schema(description = "租户ID,为空时取当前请求租户;仍为空则拒绝写库") private String tenantId; @Schema(description = "关联小程序用户ID(blade_mp_user.id)") diff --git a/blade-service-api/blade-user-api/src/main/java/org/springblade/system/pojo/dto/MpUserEnsureDTO.java b/blade-service-api/blade-user-api/src/main/java/org/springblade/system/pojo/dto/MpUserEnsureDTO.java index adb27378..ea38a27c 100644 --- a/blade-service-api/blade-user-api/src/main/java/org/springblade/system/pojo/dto/MpUserEnsureDTO.java +++ b/blade-service-api/blade-user-api/src/main/java/org/springblade/system/pojo/dto/MpUserEnsureDTO.java @@ -43,7 +43,7 @@ public class MpUserEnsureDTO implements Serializable { @Serial private static final long serialVersionUID = 1L; - @Schema(description = "租户ID,为空时依次取当前登录租户与默认租户") + @Schema(description = "租户ID,为空时依次取 Tenant-Id 请求头与默认租户") private String tenantId; @Schema(description = "手机号") diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/MpUserServiceImpl.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/MpUserServiceImpl.java index c1e77ca9..125b63ce 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/MpUserServiceImpl.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/MpUserServiceImpl.java @@ -24,6 +24,7 @@ package org.springblade.system.service.impl; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springblade.common.utils.PasswordRuleUtil; @@ -35,6 +36,7 @@ import org.springblade.core.tool.utils.DateUtil; import org.springblade.core.tool.utils.DigestUtil; import org.springblade.core.tool.utils.Func; import org.springblade.core.tool.utils.StringUtil; +import org.springblade.core.tool.utils.WebUtil; import org.springblade.system.cache.MpUserCache; import org.springblade.system.mapper.MpUserMapper; import org.springblade.system.pojo.dto.MpUserEnsureDTO; @@ -65,6 +67,11 @@ public class MpUserServiceImpl extends BaseServiceImpl imp */ private static final String DEFAULT_TENANT_ID = "000000"; + /** + * 登录请求携带租户的请求头名 + */ + private static final String TENANT_HEADER = "Tenant-Id"; + @Override public MpUser getByPhone(String tenantId, String phone) { if (Func.isBlank(tenantId) || Func.isBlank(phone)) { @@ -127,12 +134,12 @@ public class MpUserServiceImpl extends BaseServiceImpl imp user.setStatus(1); prepare(user); validate(user); - // 登录路径不设密码:密码留空,避免调用方误传弱口令 + // 登录路径不设密码,password 保持为空 user.setPassword(null); try { save(user); } catch (Exception exception) { - // 并发建号撞 (tenant_id, phone) 唯一键:重读一次返回,登录方不该因重试失败 + // 并发建号撞 (tenant_id, phone) 唯一键:重读一次并返回已有账号 MpUser concurrent = getByPhone(tenantId, phone); if (concurrent != null && Func.isNotEmpty(concurrent.getId())) { return concurrent; @@ -148,15 +155,15 @@ public class MpUserServiceImpl extends BaseServiceImpl imp } /** - * 登录路径的租户解析:入参 → 当前登录租户 → 默认租户 + * 登录路径的租户解析:Tenant-Id 头 → 入参 tenantId → 默认租户 *

- * 写库前必须得到非空值:唯一键 (tenant_id, phone) 对 NULL 不去重,租户为 NULL - * 会为同一手机号造出重复账号。 + * 请求头与入参不一致时以请求头为准。写库前必须得到非空值:唯一键 (tenant_id, phone) + * 对 NULL 不去重,租户为 NULL 会为同一手机号造出重复账号。 */ private String resolveEnsureTenantId(String tenantId) { - String resolved = trimToNull(tenantId); + String resolved = requestHeaderTenantId(); if (resolved == null) { - resolved = trimToNull(AuthUtil.getTenantId()); + resolved = trimToNull(tenantId); } if (resolved == null) { resolved = DEFAULT_TENANT_ID; @@ -164,6 +171,17 @@ public class MpUserServiceImpl extends BaseServiceImpl imp return resolved; } + /** + * 当前请求头里的租户;无请求上下文时返回 null + */ + private String requestHeaderTenantId() { + HttpServletRequest request = WebUtil.getRequest(); + if (request == null) { + return null; + } + return trimToNull(request.getHeader(TENANT_HEADER)); + } + @Override public MpUserInfo userInfo(Long userId) { if (Func.isEmpty(userId)) { @@ -319,8 +337,8 @@ public class MpUserServiceImpl extends BaseServiceImpl imp if (!tenantId.equals(user.getTenantId())) { throw new ServiceException("租户不匹配,无法绑定 openid"); } - // 目标账号已有另一个非空 openid 时不得覆盖:旧逻辑会静默顶掉上一个微信的绑定, - // 而一个微信换绑需要管理员确认,登录路径只放弃本次绑定(票 05) + // 目标账号已有另一个非空 openid 时不覆盖:一个微信换绑由管理员处理, + // 登录路径直接放弃本次绑定 if (Func.isNotBlank(user.getOpenid()) && !user.getOpenid().equals(openid)) { log.warn("小程序用户已绑定其他 openid,跳过绑定:租户={} 账号={} 已有openid={} 本次openid={}", tenantId, userId, user.getOpenid(), openid);