From d521f55b1d4b08c0509cd0107a9245acf3cca7ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E9=B9=8F?= <812968653@qq.com> Date: Sun, 6 Sep 2026 12:54:57 +0800 Subject: [PATCH] =?UTF-8?q?bug=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/auth/AppAuthController.java | 15 +++--- .../airline/MemberAirlineAccountMapper.java | 7 +++ .../airline/MemberAirlineAccountService.java | 9 ++-- .../MemberAirlineAccountServiceImpl.java | 50 +++++++++++++++++-- .../service/auth/MemberAuthService.java | 9 ++-- .../service/auth/MemberAuthServiceImpl.java | 4 +- 6 files changed, 75 insertions(+), 19 deletions(-) diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java index 2fc2885..067278a 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java @@ -57,15 +57,16 @@ public class AppAuthController { } @GetMapping("/airline-check") - @Operation(summary = "航空账号会话校验(免登录,按手机号+渠道+设备识别号核对账号)") - @Parameter(name = "mobile", description = "手机号", required = true) + @Operation(summary = "航空账号会话校验(免登录,兼容新旧客户端:Token/手机号+渠道/设备识别号 任一定位)") @Parameter(name = "deviceId", description = "设备唯一识别号", required = true) - @Parameter(name = "channel", description = "品牌渠道(CZ/MU/HU)", required = true) + @Parameter(name = "mobile", description = "手机号(新客户端传)") + @Parameter(name = "channel", description = "品牌渠道 CZ/MU/HU(新客户端传)") @PermitAll - public CommonResult airlineCheck(@RequestParam("mobile") String mobile, - @RequestParam("deviceId") String deviceId, - @RequestParam("channel") String channel) { - authService.airlineCheck(mobile, deviceId, channel); + public CommonResult airlineCheck( + @RequestParam(value = "mobile", required = false) String mobile, + @RequestParam("deviceId") String deviceId, + @RequestParam(value = "channel", required = false) String channel) { + authService.airlineCheck(getLoginUserId(), mobile, deviceId, channel); return success(true); } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/airline/MemberAirlineAccountMapper.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/airline/MemberAirlineAccountMapper.java index e8490cf..d08585a 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/airline/MemberAirlineAccountMapper.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/airline/MemberAirlineAccountMapper.java @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.member.controller.admin.airline.vo.MemberAirlineA import cn.iocoder.yudao.module.member.dal.dataobject.airline.MemberAirlineAccountDO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + @Mapper public interface MemberAirlineAccountMapper extends BaseMapperX { @@ -32,4 +34,9 @@ public interface MemberAirlineAccountMapper extends BaseMapperX selectListByDeviceId(String deviceId) { + return selectList(new LambdaQueryWrapperX() + .eq(MemberAirlineAccountDO::getDeviceId, deviceId)); + } + } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/airline/MemberAirlineAccountService.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/airline/MemberAirlineAccountService.java index d21acb8..cbf41b2 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/airline/MemberAirlineAccountService.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/airline/MemberAirlineAccountService.java @@ -34,9 +34,12 @@ public interface MemberAirlineAccountService { MemberAirlineAccountDO authenticateAndBindDevice(String mobile, String password, String deviceId, String channel); /** - * 会话校验(免登录):按 手机号+渠道 定位账号,校验存在/禁用/有效期/设备绑定。 - * 不依赖任何 Token,App 每次打开直接核对账号表。 + * 会话校验(免登录,兼容新旧客户端): + * ① Token 有效 → 按登录用户(航空账号编号)定位; + * ② Token 失效但传了 手机号+渠道 → 按账号表定位; + * ③ 都没有 → 仅按设备识别号兜底(设备绑定的任一有效账号即放行)。 + * 校验内容:账号存在、未禁用、在有效期内、设备绑定匹配。 */ - void validateAirlineSession(String mobile, String deviceId, String channel); + void validateAirlineSession(Long loginUserId, String mobile, String deviceId, String channel); } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/airline/MemberAirlineAccountServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/airline/MemberAirlineAccountServiceImpl.java index 6f9c168..f7fe46d 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/airline/MemberAirlineAccountServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/airline/MemberAirlineAccountServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.member.service.airline; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.member.controller.admin.airline.vo.MemberAirlineAccountCreateReqVO; @@ -16,6 +17,8 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -123,12 +126,51 @@ public class MemberAirlineAccountServiceImpl implements MemberAirlineAccountServ } @Override - public void validateAirlineSession(String mobile, String deviceId, String channel) { - // 按 手机号+渠道 定位账号(免 Token 校验,直接核对账号表) - MemberAirlineAccountDO account = airlineAccountMapper.selectByMobileAndChannel(mobile, channel); - if (account == null) { + public void validateAirlineSession(Long loginUserId, String mobile, String deviceId, String channel) { + // ① 手机号+渠道:精确匹配,直接认定是本人账号 + if (StrUtil.isNotBlank(mobile) && StrUtil.isNotBlank(channel)) { + MemberAirlineAccountDO account = airlineAccountMapper.selectByMobileAndChannel(mobile, channel); + if (account == null) { + throw exception(AIRLINE_ACCOUNT_NOT_EXISTS); + } + validateAccount(account, deviceId); + return; + } + + // 收集候选账号:② Token 定位 + ③ 设备识别号定位(两者合并,逐个核实) + // 注意:旧 Token(member_user 同步方案时期签发)的 userId 是 member_user 编号, + // 与 member_airline_account 的 id 共用数字空间,selectById 可能撞号命中别人的账号, + // 因此候选必须经过"设备匹配"核实身份后,才能采信其状态。 + List candidates = new ArrayList<>(); + if (loginUserId != null) { + MemberAirlineAccountDO account = airlineAccountMapper.selectById(loginUserId); + if (account != null) { + candidates.add(account); + } + } + for (MemberAirlineAccountDO account : airlineAccountMapper.selectListByDeviceId(deviceId)) { + if (candidates.stream().noneMatch(c -> Objects.equals(c.getId(), account.getId()))) { + candidates.add(account); + } + } + if (candidates.isEmpty()) { throw exception(AIRLINE_ACCOUNT_NOT_EXISTS); } + + // 逐个候选核实:设备不匹配说明不是本机绑定的账号(如旧 Token 撞号),跳过换下一个; + // 设备匹配后才校验状态,此时报"禁用/到期"才是真实问题 + for (MemberAirlineAccountDO account : candidates) { + if (StrUtil.isBlank(account.getDeviceId()) || !StrUtil.equals(account.getDeviceId(), deviceId)) { + continue; + } + validateAccount(account, deviceId); + return; + } + // 所有候选的绑定设备都与本机不符 + throw exception(AIRLINE_ACCOUNT_DEVICE_BOUND); + } + + private void validateAccount(MemberAirlineAccountDO account, String deviceId) { if (CommonStatusEnum.isDisable(account.getStatus())) { throw exception(AIRLINE_ACCOUNT_DISABLED); } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java index f68273d..16137fc 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java @@ -116,9 +116,12 @@ public interface MemberAuthService { AppAuthLoginRespVO airlineLogin(@Valid AppAuthAirlineLoginReqVO reqVO); /** - * 航空账号会话校验(免登录):按 手机号+渠道+设备识别号 定位账号, - * 校验账号存在、未禁用、在有效期内、设备绑定匹配。不依赖任何 Token。 + * 航空账号会话校验(免登录,兼容新旧客户端): + * ① Token 有效 → 按登录用户定位账号校验; + * ② Token 失效但传了 手机号+渠道 → 按账号表定位校验; + * ③ 都没有 → 仅按设备识别号兜底(设备绑定的任一有效账号即放行)。 + * 校验内容:账号存在、未禁用、在有效期内、设备绑定匹配。 */ - void airlineCheck(String mobile, String deviceId, String channel); + void airlineCheck(Long loginUserId, String mobile, String deviceId, String channel); } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java index 6e03e18..c06220f 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java @@ -453,8 +453,8 @@ public class MemberAuthServiceImpl implements MemberAuthService { } @Override - public void airlineCheck(String mobile, String deviceId, String channel) { - airlineAccountService.validateAirlineSession(mobile, deviceId, channel); + public void airlineCheck(Long loginUserId, String mobile, String deviceId, String channel) { + airlineAccountService.validateAirlineSession(loginUserId, mobile, deviceId, channel); } private void createLogoutLog(Long userId) {