diff --git a/client-api/src/main/java/org/jiayunet/controller/LoginController.java b/client-api/src/main/java/org/jiayunet/controller/LoginController.java index 77ea739..7719393 100644 --- a/client-api/src/main/java/org/jiayunet/controller/LoginController.java +++ b/client-api/src/main/java/org/jiayunet/controller/LoginController.java @@ -2,6 +2,7 @@ package org.jiayunet.controller; import lombok.AllArgsConstructor; import org.jiayunet.pojo.dto.SmsLoginDto; +import org.jiayunet.pojo.dto.SuperAdminLoginDto; import org.jiayunet.pojo.vo.LoginVo; import org.jiayunet.service.LoginService; import org.jiayunet.tool.UserSecurityTool; @@ -37,6 +38,17 @@ public class LoginController { return loginService.smsLogin(dto.getMobileNumber(), dto.getCode(), dto.getInviteCode(), request, response); } + /** + * 超管密码登录 + *

用手机号+超管密码直接登录,用户不存在则自动注册并赠送正式会员

+ */ + @PostMapping("/login/superAdminLogin") + public LoginVo superAdminLogin(@Validated @RequestBody SuperAdminLoginDto dto, + HttpServletRequest request, + HttpServletResponse response) { + return loginService.superAdminLogin(dto.getMobileNumber(), dto.getPassword(), request, response); + } + @PostMapping("/logout") public boolean logout(HttpServletRequest request, HttpServletResponse response) { loginService.logout(request, response); diff --git a/client-api/src/main/java/org/jiayunet/pojo/dto/SuperAdminLoginDto.java b/client-api/src/main/java/org/jiayunet/pojo/dto/SuperAdminLoginDto.java new file mode 100644 index 0000000..942bb13 --- /dev/null +++ b/client-api/src/main/java/org/jiayunet/pojo/dto/SuperAdminLoginDto.java @@ -0,0 +1,22 @@ +package org.jiayunet.pojo.dto; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + +/** + * 超管密码登录入参 + * + * @author zk + */ +@Data +public class SuperAdminLoginDto { + + @NotBlank(message = "手机号不能为空") + @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确") + private String mobileNumber; + + @NotBlank(message = "超管密码不能为空") + private String password; +} diff --git a/client-api/src/main/java/org/jiayunet/service/LoginService.java b/client-api/src/main/java/org/jiayunet/service/LoginService.java index b040e60..3a00c9a 100644 --- a/client-api/src/main/java/org/jiayunet/service/LoginService.java +++ b/client-api/src/main/java/org/jiayunet/service/LoginService.java @@ -22,6 +22,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; @@ -33,7 +34,7 @@ import java.util.stream.Collectors; /** * 登录服务 - *

依赖:SmsService(验证码发送与校验)、UserRegisterService(自动注册)

+ *

依赖:SmsService(验证码发送与校验)、UserRegisterService(自动注册/超管注册)

*

使用表:bg_user(查询/创建用户)

*

使用Redis:login:token:{userId}(登录令牌与多设备管理)

* @@ -52,6 +53,9 @@ public class LoginService { @Value("${app.login.device_online_quantity:5}") private int deviceOnlineQuantity; + @Value("${app.super_admin.password:}") + private String superAdminPassword; + @Autowired private SmsService smsService; @@ -106,6 +110,65 @@ public class LoginService { throw new BusinessException(BusinessExpCodeEnum.UNKNOWN_ERROR, "账号已被禁用"); } + // 清除验证码 + smsService.clear(mobileNumber, SmsTemplateEnum.UNIVERSAL); + + + return doLogin(user, request, response); + } + + /** + * 超管密码登录 + *

1. 校验超管密码 2. 查询用户,不存在则走超管注册 3. 检查用户状态 4. 完成登录(签发令牌、多设备管理、写Cookie)

+ * + * @param mobileNumber 手机号 + * @param password 超管密码,取 app.super_admin.password,未配置时禁用该登录方式 + */ + @Transactional(rollbackFor = Exception.class) + public LoginVo superAdminLogin(String mobileNumber, String password, HttpServletRequest request, HttpServletResponse response) { + Assert.hasText(mobileNumber, "手机号不能为空"); + Assert.hasText(password, "超管密码不能为空"); + + // 未配置超管密码时该登录方式不可用 + if (!StringUtils.hasText(superAdminPassword)) { + log.warn("超管登录被拒绝:未配置超管密码 mobileNumber:{}", mobileNumber); + throw new BusinessException(BusinessExpCodeEnum.UNKNOWN_ERROR, "超管密码错误"); + } + + // 校验超管密码 + if (!superAdminPassword.equals(password)) { + log.warn("超管登录密码错误 mobileNumber:{} ip:{}", mobileNumber, HttpIpTool.gteRealIP(request)); + throw new BusinessException(BusinessExpCodeEnum.UNKNOWN_ERROR, "超管密码错误"); + } + + // 查询用户 + User user = userMapper.selectOne(new LambdaQueryWrapper().eq(User::getMobileNumber, mobileNumber)); + + // 用户不存在则走超管注册 + if (user == null) { + user = userRegisterService.supperMasterRegister(mobileNumber); + } + + // 检查用户状态 + if (user.getStatus() != null && user.getStatus() == 1) { + throw new BusinessException(BusinessExpCodeEnum.UNKNOWN_ERROR, "账号已被禁用"); + } + + log.info("超管登录成功 userId:{} mobileNumber:{} ip:{}", user.getId(), mobileNumber, HttpIpTool.gteRealIP(request)); + + return doLogin(user, request, response); + } + + /** + * 完成登录:签发令牌、维护多设备在线、写入Cookie + *

1. 生成uuId并签发JWT 2. 读取或初始化Redis登录信息 3. 过滤过期设备并按上限剔除最早设备 4. 追加当前设备后回写Redis 5. 设置Token Cookie

+ * + * @param user 已通过身份校验的用户 + * @param request 用于获取真实登录IP + * @param response 用于写入Token Cookie + * @return 登录结果 + */ + public LoginVo doLogin(User user, HttpServletRequest request, HttpServletResponse response) { // 生成JWT String uuId = UUID.randomUUID().toString().replace("-", ""); Algorithm algorithm = Algorithm.HMAC256(secret); @@ -150,8 +213,6 @@ public class LoginService { info.setLoginDevices(devices); redisServerTool.set(redisKey, info, tokenExceedTime, TimeUnit.SECONDS); - // 清除验证码 - smsService.clear(mobileNumber, SmsTemplateEnum.UNIVERSAL); // 设置Cookie Cookie cookie = new Cookie("Token", token); diff --git a/client-api/src/main/java/org/jiayunet/service/UserRegisterService.java b/client-api/src/main/java/org/jiayunet/service/UserRegisterService.java index ae658fb..6957fea 100644 --- a/client-api/src/main/java/org/jiayunet/service/UserRegisterService.java +++ b/client-api/src/main/java/org/jiayunet/service/UserRegisterService.java @@ -67,6 +67,37 @@ public class UserRegisterService { @Value("${app.reward.invite-milestone-days:150}") private int inviteMilestoneDays; + @Value("${app.super_admin.register_gift_days:365}") + private int superAdminRegisterGiftDays; + + /** + * 超级管理注册新用户 + *

1. 创建用户并生成邀请码 2. 发放会员,天数取 app.super_admin.register_gift_days

+ * + * @param mobileNumber 手机号 + * @return 新注册的用户 + */ + @Transactional(rollbackFor = Exception.class) + public User supperMasterRegister(String mobileNumber) { + // 创建用户 + User user = new User(); + user.setMobileNumber(mobileNumber); + user.setNick("用户" + mobileNumber.substring(mobileNumber.length() - 4)); + user.setInviteCode(generateInviteCode()); + user.setStatus(0); + user.setIsDelete(0L); + user.setCreateTime(Instant.now()); + userMapper.insert(user); + + + // 发放新用户注册会员权益 + memberGrantService.grant(user.getId(), superAdminRegisterGiftDays, 1); // 1=正式 + messageService.sendToUser(1, user.getId(), "欢迎加入OfferPie", "注册成功,已赠送您" + superAdminRegisterGiftDays + "天会员权益,快来体验AI求职助手吧!", null, null); + + return user; + } + + /** * 注册新用户 *

1. 创建用户并生成邀请码 2. 若携带邀请码则绑定邀请关系

diff --git a/client-api/src/main/resources/application-dev.yml b/client-api/src/main/resources/application-dev.yml index 7c10859..2805eea 100644 --- a/client-api/src/main/resources/application-dev.yml +++ b/client-api/src/main/resources/application-dev.yml @@ -57,6 +57,13 @@ app: #设备在线数量 device_online_quantity: 3 + # 超级管理配置 + super_admin: + # 超级管理密码(可绕过验证码直接登录,务必通过环境变量注入) + password: ${SUPER_ADMIN_PASSWORD:H7KQ2XR9LP} + # 超级管理注册赠送会员天数 + register_gift_days: ${SUPER_ADMIN_REGISTER_GIFT_DAYS:365} + # 短信 sms: service_provider: aliyun diff --git a/client-api/src/main/resources/application-prod.yml b/client-api/src/main/resources/application-prod.yml index e8f71d8..665562d 100644 --- a/client-api/src/main/resources/application-prod.yml +++ b/client-api/src/main/resources/application-prod.yml @@ -57,6 +57,13 @@ app: #设备在线数量 device_online_quantity: 3 + # 超级管理配置 + super_admin: + # 超级管理密码(可绕过验证码直接登录,务必通过环境变量注入) + password: ${SUPER_ADMIN_PASSWORD:H7KQ2XR9LP} + # 超级管理注册赠送会员天数 + register_gift_days: ${SUPER_ADMIN_REGISTER_GIFT_DAYS:365} + # 短信 sms: service_provider: aliyun diff --git a/client-api/src/main/resources/application-test.yml b/client-api/src/main/resources/application-test.yml index 5644abd..03e540c 100644 --- a/client-api/src/main/resources/application-test.yml +++ b/client-api/src/main/resources/application-test.yml @@ -58,6 +58,13 @@ app: #设备在线数量 device_online_quantity: 3 + # 超级管理配置 + super_admin: + # 超级管理密码(可绕过验证码直接登录,务必通过环境变量注入) + password: ${SUPER_ADMIN_PASSWORD:H7KQ2XR9LP} + # 超级管理注册赠送会员天数 + register_gift_days: ${SUPER_ADMIN_REGISTER_GIFT_DAYS:365} + # 短信 sms: service_provider: aliyun