From 1024045a92881f935b707c274af871e1176314f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E9=B9=8F?= <812968653@qq.com> Date: Sat, 5 Sep 2026 23:44:01 +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 --- sql/mysql/member/member_airline_account.sql | 14 +++--- .../member_airline_account_add_channel.sql | 20 +++++++++ .../vo/MemberAirlineAccountBaseVO.java | 6 +++ .../vo/MemberAirlineAccountPageReqVO.java | 3 ++ .../vo/MemberAirlineAccountRespVO.java | 3 ++ .../app/auth/vo/AppAuthAirlineLoginReqVO.java | 6 +++ .../airline/MemberAirlineAccountDO.java | 4 +- .../airline/MemberAirlineAccountMapper.java | 17 +++---- .../airline/MemberAirlineAccountService.java | 11 +++-- .../MemberAirlineAccountServiceImpl.java | 32 ++++++-------- .../service/auth/MemberAuthServiceImpl.java | 44 ++++++++++++------- 11 files changed, 104 insertions(+), 56 deletions(-) create mode 100644 sql/mysql/member/member_airline_account_add_channel.sql diff --git a/sql/mysql/member/member_airline_account.sql b/sql/mysql/member/member_airline_account.sql index f186882..25f92d4 100644 --- a/sql/mysql/member/member_airline_account.sql +++ b/sql/mysql/member/member_airline_account.sql @@ -1,14 +1,15 @@ -- 航空账号(管理员开通:手机号+密码+有效期+设备唯一绑定) CREATE TABLE IF NOT EXISTS `member_airline_account` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', - `mobile` varchar(11) NOT NULL COMMENT '手机号', + `mobile` varchar(11) NOT NULL COMMENT '手机号(同一手机号可在不同渠道各有一个账号)', + `channel` varchar(8) NOT NULL DEFAULT 'CZ' COMMENT '品牌渠道(CZ南航/MU东航/HU海航)', `password` varchar(100) NOT NULL DEFAULT '' COMMENT '密码(BCrypt)', `start_time` datetime NOT NULL COMMENT '生效开始时间', `end_time` datetime NOT NULL COMMENT '生效结束时间', `device_id` varchar(128) NULL DEFAULT NULL COMMENT '手机唯一识别号(首次登录绑定;重装/重启应由客户端保持不变)', `status` tinyint NOT NULL DEFAULT 0 COMMENT '状态(0开启 1关闭)', `remark` varchar(500) NULL DEFAULT NULL COMMENT '备注', - `user_id` bigint NULL DEFAULT NULL COMMENT '关联会员用户编号 member_user.id', + `user_id` bigint NULL DEFAULT NULL COMMENT '关联会员用户编号 member_user.id(已废弃,登录不再创建会员用户)', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `creator` varchar(64) NULL DEFAULT '' COMMENT '创建者', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', @@ -16,8 +17,8 @@ CREATE TABLE IF NOT EXISTS `member_airline_account` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE, - UNIQUE KEY `uk_mobile` (`mobile`, `deleted`, `tenant_id`) USING BTREE, - UNIQUE KEY `uk_device_id` (`device_id`, `deleted`, `tenant_id`) USING BTREE, + UNIQUE KEY `uk_mobile_channel` (`mobile`, `channel`, `deleted`, `tenant_id`) USING BTREE, + UNIQUE KEY `uk_channel_device` (`channel`, `device_id`, `deleted`, `tenant_id`) USING BTREE, KEY `idx_end_time` (`end_time`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='航空账号'; @@ -40,8 +41,9 @@ ON DUPLICATE KEY UPDATE `permission` = VALUES(`permission`); -- 手机号:13800138000 密码:123456 有效期约一年 未绑定设备 -- 密码哈希为 BCrypt(123456) INSERT INTO `member_airline_account` -(`mobile`, `password`, `start_time`, `end_time`, `device_id`, `status`, `remark`, `user_id`, `tenant_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) +(`mobile`, `channel`, `password`, `start_time`, `end_time`, `device_id`, `status`, `remark`, `user_id`, `tenant_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) SELECT '13800138000', + 'CZ', '$2a$10$PplOV8yXcQo9xc32V8vwTuIMbMKgNtjXf3lu6l18LUTOy9YGDdAY6', NOW() - INTERVAL 1 DAY, NOW() + INTERVAL 365 DAY, @@ -58,5 +60,5 @@ SELECT '13800138000', FROM DUAL WHERE NOT EXISTS ( SELECT 1 FROM `member_airline_account` - WHERE `mobile` = '13800138000' AND `deleted` = b'0' AND `tenant_id` = 1 + WHERE `mobile` = '13800138000' AND `channel` = 'CZ' AND `deleted` = b'0' AND `tenant_id` = 1 ); diff --git a/sql/mysql/member/member_airline_account_add_channel.sql b/sql/mysql/member/member_airline_account_add_channel.sql new file mode 100644 index 0000000..215570e --- /dev/null +++ b/sql/mysql/member/member_airline_account_add_channel.sql @@ -0,0 +1,20 @@ +-- 航空账号增加品牌渠道(channel):CZ 南航 / MU 东航 / HU 海航 +-- 目的:三个 App 使用同一手机号分别登录,互不干扰。 +-- 唯一键调整: +-- uk_mobile (mobile, deleted, tenant_id) -> 废弃 +-- uk_device_id (device_id, deleted, tenant_id) -> 废弃 +-- uk_mobile_channel (mobile, channel, deleted, tenant_id) -> 同一手机号每渠道一个账号 +-- uk_channel_device (channel, device_id, deleted, tenant_id) -> 同一设备每渠道绑定一个账号 + +ALTER TABLE `member_airline_account` + ADD COLUMN `channel` varchar(8) NOT NULL DEFAULT 'CZ' COMMENT '品牌渠道(CZ南航/MU东航/HU海航)' AFTER `mobile`; + +-- 存量数据归属渠道默认回填为 CZ(南航),如实际属于东航/海航请手工执行: +-- UPDATE `member_airline_account` SET `channel` = 'MU' WHERE ...; +-- UPDATE `member_airline_account` SET `channel` = 'HU' WHERE ...; + +ALTER TABLE `member_airline_account` + DROP INDEX `uk_mobile`, + DROP INDEX `uk_device_id`, + ADD UNIQUE KEY `uk_mobile_channel` (`mobile`, `channel`, `deleted`, `tenant_id`), + ADD UNIQUE KEY `uk_channel_device` (`channel`, `device_id`, `deleted`, `tenant_id`); diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/airline/vo/MemberAirlineAccountBaseVO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/airline/vo/MemberAirlineAccountBaseVO.java index 8f45fb4..3fc137a 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/airline/vo/MemberAirlineAccountBaseVO.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/airline/vo/MemberAirlineAccountBaseVO.java @@ -7,6 +7,7 @@ import org.springframework.format.annotation.DateTimeFormat; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @@ -20,6 +21,11 @@ public class MemberAirlineAccountBaseVO { @Length(min = 11, max = 11, message = "手机号长度为 11 位") private String mobile; + @Schema(description = "品牌渠道(CZ南航/MU东航/HU海航)", requiredMode = Schema.RequiredMode.REQUIRED, example = "CZ") + @NotEmpty(message = "品牌渠道不能为空") + @Pattern(regexp = "CZ|MU|HU", message = "品牌渠道仅支持 CZ(南航)/ MU(东航)/ HU(海航)") + private String channel; + @Schema(description = "生效开始时间", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "开始时间不能为空") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/airline/vo/MemberAirlineAccountPageReqVO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/airline/vo/MemberAirlineAccountPageReqVO.java index 6ac8038..49fb3a5 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/airline/vo/MemberAirlineAccountPageReqVO.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/airline/vo/MemberAirlineAccountPageReqVO.java @@ -20,6 +20,9 @@ public class MemberAirlineAccountPageReqVO extends PageParam { @Schema(description = "手机号", example = "13800138000") private String mobile; + @Schema(description = "品牌渠道(CZ南航/MU东航/HU海航)", example = "CZ") + private String channel; + @Schema(description = "状态(0开启 1关闭)", example = "0") private Integer status; diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/airline/vo/MemberAirlineAccountRespVO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/airline/vo/MemberAirlineAccountRespVO.java index 1ced489..4268a5f 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/airline/vo/MemberAirlineAccountRespVO.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/airline/vo/MemberAirlineAccountRespVO.java @@ -15,6 +15,9 @@ public class MemberAirlineAccountRespVO { @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13800138000") private String mobile; + @Schema(description = "品牌渠道(CZ南航/MU东航/HU海航)", requiredMode = Schema.RequiredMode.REQUIRED, example = "CZ") + private String channel; + @Schema(description = "生效开始时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime startTime; diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthAirlineLoginReqVO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthAirlineLoginReqVO.java index ea91ddee..c787f0a 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthAirlineLoginReqVO.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthAirlineLoginReqVO.java @@ -6,6 +6,7 @@ import lombok.Data; import org.hibernate.validator.constraints.Length; import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; @Schema(description = "用户 APP - 航空账号登录 Request VO") @Data @@ -16,6 +17,11 @@ public class AppAuthAirlineLoginReqVO { @Mobile private String mobile; + @Schema(description = "品牌渠道", requiredMode = Schema.RequiredMode.REQUIRED, example = "CZ") + @NotEmpty(message = "品牌渠道不能为空") + @Pattern(regexp = "CZ|MU|HU", message = "品牌渠道仅支持 CZ(南航)/ MU(东航)/ HU(海航)") + private String channel; + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") @NotEmpty(message = "密码不能为空") @Length(min = 4, max = 16, message = "密码长度为 4-16 位") diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/airline/MemberAirlineAccountDO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/airline/MemberAirlineAccountDO.java index fd9a68a..8c87ae1 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/airline/MemberAirlineAccountDO.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/airline/MemberAirlineAccountDO.java @@ -23,8 +23,10 @@ public class MemberAirlineAccountDO extends TenantBaseDO { @TableId private Long id; - /** 手机号 */ + /** 手机号(同一手机号可在不同渠道各有一个账号) */ private String mobile; + /** 品牌渠道:CZ 南航 / MU 东航 / HU 海航 */ + private String channel; /** 密码(BCrypt) */ private String password; /** 生效开始时间 */ 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 eb3bf79..e8490cf 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 @@ -13,22 +13,23 @@ public interface MemberAirlineAccountMapper extends BaseMapperX selectPage(MemberAirlineAccountPageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(MemberAirlineAccountDO::getMobile, reqVO.getMobile()) + .eqIfPresent(MemberAirlineAccountDO::getChannel, reqVO.getChannel()) .eqIfPresent(MemberAirlineAccountDO::getStatus, reqVO.getStatus()) .likeIfPresent(MemberAirlineAccountDO::getDeviceId, reqVO.getDeviceId()) .betweenIfPresent(MemberAirlineAccountDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(MemberAirlineAccountDO::getId)); } - default MemberAirlineAccountDO selectByMobile(String mobile) { - return selectOne(MemberAirlineAccountDO::getMobile, mobile); + default MemberAirlineAccountDO selectByMobileAndChannel(String mobile, String channel) { + return selectOne(new LambdaQueryWrapperX() + .eq(MemberAirlineAccountDO::getMobile, mobile) + .eq(MemberAirlineAccountDO::getChannel, channel)); } - default MemberAirlineAccountDO selectByDeviceId(String deviceId) { - return selectOne(MemberAirlineAccountDO::getDeviceId, deviceId); - } - - default MemberAirlineAccountDO selectByUserId(Long userId) { - return selectOne(MemberAirlineAccountDO::getUserId, userId); + default MemberAirlineAccountDO selectByDeviceIdAndChannel(String deviceId, String channel) { + return selectOne(new LambdaQueryWrapperX() + .eq(MemberAirlineAccountDO::getDeviceId, deviceId) + .eq(MemberAirlineAccountDO::getChannel, channel)); } } 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 2ccc741..82b13e8 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 @@ -26,18 +26,17 @@ public interface MemberAirlineAccountService { /** 管理端解绑设备,允许换机重新登录绑定 */ void unbindDevice(Long id); - /** 登录成功后回写关联的会员用户编号 */ - void updateAirlineAccountUserId(Long id, Long userId); - /** * 登录校验:密码、有效期、设备绑定。 - * 首次登录绑定 deviceId;成功后返回账号(可能已写入 deviceId / userId)。 + * 手机号与设备号均按渠道(channel)隔离:同一手机号/同一设备可在 CZ/MU/HU 各绑定一个账号。 + * 首次登录绑定 deviceId;成功后返回账号(可能已写入 deviceId)。 */ - MemberAirlineAccountDO authenticateAndBindDevice(String mobile, String password, String deviceId); + MemberAirlineAccountDO authenticateAndBindDevice(String mobile, String password, String deviceId, String channel); /** * 会话校验:已登录用户打开 App 时检查账号是否禁用/过期/设备不匹配。 + * 注意:accountId 为登录 Token 中的 userId,即航空账号自身编号(不再是 member_user 编号)。 */ - void validateAirlineSession(Long userId, String deviceId); + void validateAirlineSession(Long accountId, String deviceId); } 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 d0fe7db..34048f5 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 @@ -33,7 +33,7 @@ public class MemberAirlineAccountServiceImpl implements MemberAirlineAccountServ @Override public Long createAirlineAccount(MemberAirlineAccountCreateReqVO createReqVO) { validateTimeRange(createReqVO.getStartTime(), createReqVO.getEndTime()); - validateMobileUnique(null, createReqVO.getMobile()); + validateMobileUnique(null, createReqVO.getMobile(), createReqVO.getChannel()); MemberAirlineAccountDO account = BeanUtils.toBean(createReqVO, MemberAirlineAccountDO.class); account.setPassword(passwordEncoder.encode(createReqVO.getPassword())); @@ -46,7 +46,7 @@ public class MemberAirlineAccountServiceImpl implements MemberAirlineAccountServ public void updateAirlineAccount(MemberAirlineAccountUpdateReqVO updateReqVO) { validateExists(updateReqVO.getId()); validateTimeRange(updateReqVO.getStartTime(), updateReqVO.getEndTime()); - validateMobileUnique(updateReqVO.getId(), updateReqVO.getMobile()); + validateMobileUnique(updateReqVO.getId(), updateReqVO.getMobile(), updateReqVO.getChannel()); MemberAirlineAccountDO updateObj = BeanUtils.toBean(updateReqVO, MemberAirlineAccountDO.class); if (StrUtil.isBlank(updateReqVO.getPassword())) { @@ -83,18 +83,10 @@ public class MemberAirlineAccountServiceImpl implements MemberAirlineAccountServ .set(MemberAirlineAccountDO::getDeviceId, null)); } - @Override - public void updateAirlineAccountUserId(Long id, Long userId) { - MemberAirlineAccountDO update = new MemberAirlineAccountDO(); - update.setId(id); - update.setUserId(userId); - airlineAccountMapper.updateById(update); - } - @Override @Transactional(rollbackFor = Exception.class) - public MemberAirlineAccountDO authenticateAndBindDevice(String mobile, String password, String deviceId) { - MemberAirlineAccountDO account = airlineAccountMapper.selectByMobile(mobile); + public MemberAirlineAccountDO authenticateAndBindDevice(String mobile, String password, String deviceId, String channel) { + MemberAirlineAccountDO account = airlineAccountMapper.selectByMobileAndChannel(mobile, channel); if (account == null) { throw exception(AIRLINE_ACCOUNT_BAD_CREDENTIALS); } @@ -114,8 +106,8 @@ public class MemberAirlineAccountServiceImpl implements MemberAirlineAccountServ String boundDeviceId = account.getDeviceId(); if (StrUtil.isBlank(boundDeviceId)) { - // 首次绑定:设备不能已被其他账号占用 - MemberAirlineAccountDO byDevice = airlineAccountMapper.selectByDeviceId(deviceId); + // 首次绑定:同渠道下设备不能已被其他账号占用(不同渠道互不影响) + MemberAirlineAccountDO byDevice = airlineAccountMapper.selectByDeviceIdAndChannel(deviceId, channel); if (byDevice != null && !Objects.equals(byDevice.getId(), account.getId())) { throw exception(AIRLINE_ACCOUNT_DEVICE_USED); } @@ -131,11 +123,12 @@ public class MemberAirlineAccountServiceImpl implements MemberAirlineAccountServ } @Override - public void validateAirlineSession(Long userId, String deviceId) { - if (userId == null) { + public void validateAirlineSession(Long accountId, String deviceId) { + if (accountId == null) { throw exception(AIRLINE_ACCOUNT_NOT_EXISTS); } - MemberAirlineAccountDO account = airlineAccountMapper.selectByUserId(userId); + // 登录签发的 Token 中 userId 即航空账号自身编号 + MemberAirlineAccountDO account = airlineAccountMapper.selectById(accountId); if (account == null) { throw exception(AIRLINE_ACCOUNT_NOT_EXISTS); } @@ -164,8 +157,9 @@ public class MemberAirlineAccountServiceImpl implements MemberAirlineAccountServ return account; } - private void validateMobileUnique(Long id, String mobile) { - MemberAirlineAccountDO exist = airlineAccountMapper.selectByMobile(mobile); + private void validateMobileUnique(Long id, String mobile, String channel) { + // 同一手机号允许在不同渠道各建一个账号(CZ/MU/HU 互不干扰) + MemberAirlineAccountDO exist = airlineAccountMapper.selectByMobileAndChannel(mobile, channel); if (exist == null) { return; } 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 dbc1b7e..62d8e5c 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 @@ -411,25 +411,37 @@ public class MemberAuthServiceImpl implements MemberAuthService { @Override @Transactional(rollbackFor = Exception.class) public AppAuthLoginRespVO airlineLogin(AppAuthAirlineLoginReqVO reqVO) { - // 1. 校验航空账号:密码、有效期、设备绑定 + // 1. 校验航空账号:渠道、密码、有效期、设备绑定(手机号/设备号均按渠道隔离) MemberAirlineAccountDO account = airlineAccountService.authenticateAndBindDevice( - reqVO.getMobile(), reqVO.getPassword(), reqVO.getDeviceId()); + reqVO.getMobile(), reqVO.getPassword(), reqVO.getDeviceId(), reqVO.getChannel()); - // 2. 同步会员用户(不存在则创建),并覆盖密码保持一致 - MemberUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), getClientIP(), getTerminal()); - Assert.notNull(user, "获取用户失败,结果为空"); - userService.updateUserPassword(user.getId(), reqVO.getPassword()); + // 2. 直接以航空账号身份签发 Token(不创建、不关联 member_user,避免污染会员表) + return createTokenAfterAirlineLoginSuccess(account, reqVO.getMobile()); + } - // 3. 回写关联会员编号 - if (!Objects.equals(account.getUserId(), user.getId())) { - MemberAirlineAccountDO update = new MemberAirlineAccountDO(); - update.setId(account.getId()); - update.setUserId(user.getId()); - airlineAccountService.updateAirlineAccountUserId(account.getId(), user.getId()); - } - - // 4. 签发 Token(与密码登录一致) - return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE, null); + /** + * 航空账号专用:签发 Token + 记录登录日志。 + * 注意:不能复用 {@link #createTokenAfterLoginSuccess} 和 {@link #createLoginLog}, + * 它们在成功时会更新 member_user(状态校验、最后登录时间),而航空账号没有对应的会员用户。 + * Token 的 userId 直接使用航空账号自身编号。 + */ + private AppAuthLoginRespVO createTokenAfterAirlineLoginSuccess(MemberAirlineAccountDO account, String mobile) { + // 插入登录日志(不更新 member_user 的最后登录信息) + LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO(); + reqDTO.setLogType(LoginLogTypeEnum.LOGIN_MOBILE.getType()); + reqDTO.setTraceId(TracerUtils.getTraceId()); + reqDTO.setUserId(account.getId()); + reqDTO.setUserType(getUserType().getValue()); + reqDTO.setUsername(mobile); + reqDTO.setUserAgent(ServletUtils.getUserAgent()); + reqDTO.setUserIp(getClientIP()); + reqDTO.setResult(LoginResultEnum.SUCCESS.getResult()); + loginLogApi.createLoginLog(reqDTO); + // 创建 Token 令牌(userId 使用航空账号自身编号) + OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO() + .setUserId(account.getId()).setUserType(getUserType().getValue()) + .setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT)); + return AuthConvert.INSTANCE.convert(accessTokenRespDTO, null); } @Override