v1.0.22 #31
@@ -65,6 +65,9 @@ public class SmsServiceImplement implements SmsService {
|
||||
NotifyQueueConfig.Sms.Captcha captchaConf = config.getSms().getCaptcha();
|
||||
|
||||
NotifyDetail detail = notifyDetailService.get(detailId);
|
||||
TimiException.required(detail, "短信验证码无效");
|
||||
TimiException.required(detail.getSendAt(), "短信验证码无效");
|
||||
TimiException.requiredTrue(NotifyDetail.MsgType.SMS == detail.getMsgType(), "短信验证码无效");
|
||||
if (Time.M * captchaConf.getTtlMinute() < Time.now() - detail.getSendAt()) {
|
||||
throw new TimiException(TimiCode.ARG_EXPIRED, "验证码过期");
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.imyeyu.api.modules.user.service.UserService;
|
||||
import com.imyeyu.api.modules.user.vo.LoginResponse;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.spring.annotation.AOPLog;
|
||||
import com.imyeyu.spring.annotation.CaptchaValid;
|
||||
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||
import com.imyeyu.spring.bean.Page;
|
||||
import com.imyeyu.spring.bean.PageResult;
|
||||
@@ -80,12 +79,11 @@ public class GaoUserController {
|
||||
|
||||
@AOPLog
|
||||
@JsonView(ResponseView.Public.class)
|
||||
@CaptchaValid
|
||||
@RequestRateLimit(value = 5, inSeconds = 60)
|
||||
@PostMapping("/invite/register")
|
||||
public LoginResponse registerByInvite(@RequestBody @Valid GaoUserInviteRegisterRequest req) {
|
||||
GaoUserInviteRegisterData data = req.getData();
|
||||
String userId = inviteService.register(data);
|
||||
String userId = inviteService.register(data, req.getDetailId(), req.getCaptcha());
|
||||
return userLoginService.login(UUID.randomUUID().toString(), userId);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ public interface GaoUserInviteService {
|
||||
/// 使用邀请注册 GAO 用户
|
||||
///
|
||||
/// @param data 注册数据
|
||||
/// @param smsDetailId 短信通知详情 ID
|
||||
/// @param smsCaptcha 短信验证码
|
||||
/// @return 注册成功的用户 ID
|
||||
String register(GaoUserInviteRegisterData data);
|
||||
String register(GaoUserInviteRegisterData data, String smsDetailId, String smsCaptcha);
|
||||
}
|
||||
|
||||
+19
-5
@@ -3,6 +3,8 @@ package com.imyeyu.api.modules.gao.service.implement;
|
||||
import com.imyeyu.api.bean.CoreRoleCode;
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||
import com.imyeyu.api.modules.common.entity.NotifyDetail;
|
||||
import com.imyeyu.api.modules.common.service.SmsService;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoUserInviteCache;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
||||
@@ -69,6 +71,7 @@ public class GaoUserInviteServiceImplement implements GaoUserInviteService {
|
||||
|
||||
private final GaoStoreService gaoStoreService;
|
||||
private final GaoUserService gaoUserService;
|
||||
private final SmsService smsService;
|
||||
private final UserLoginService userLoginService;
|
||||
private final UserRoleService userRoleService;
|
||||
private final UserService userService;
|
||||
@@ -98,9 +101,11 @@ public class GaoUserInviteServiceImplement implements GaoUserInviteService {
|
||||
logger.setUserId(inviterUserId);
|
||||
permissionChecker.checkAny(ModuleCode.GAO, GaoPermissionCode.USER_CREATE.getValue());
|
||||
Role requestedRole = roleService.get(req.getRoleId());
|
||||
boolean adminInviteGlobalManager = roleChecker.hasAny(ModuleCode.CORE, CoreRoleCode.ADMIN.name())
|
||||
boolean coreAdmin = isCoreAdmin();
|
||||
boolean adminInviteGlobalManager = coreAdmin
|
||||
&& isGlobalManagerRole(requestedRole);
|
||||
boolean globalManager = authorizationScopeService.isSystemAdmin(inviterUserId)
|
||||
|| coreAdmin
|
||||
|| roleChecker.hasAny(ModuleCode.GAO, GaoRoleCode.GLOBAL_MANAGER.name());
|
||||
boolean storeManager = !globalManager;
|
||||
GaoStore loginStore = storeManager ? gaoStoreService.getByUserId(inviterUserId) : null;
|
||||
@@ -154,7 +159,7 @@ public class GaoUserInviteServiceImplement implements GaoUserInviteService {
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public String register(GaoUserInviteRegisterData data) {
|
||||
public String register(GaoUserInviteRegisterData data, String smsDetailId, String smsCaptcha) {
|
||||
TimiException.required(data, "not found register data");
|
||||
String code = data.getCode();
|
||||
TimiException.required(code, "not found code");
|
||||
@@ -170,6 +175,9 @@ public class GaoUserInviteServiceImplement implements GaoUserInviteService {
|
||||
cache = requireValidInvite(code);
|
||||
logger.setContent(buildLogContent(cache));
|
||||
validateInviteTarget(cache);
|
||||
NotifyDetail smsDetail = smsService.captchaVerify(smsDetailId, smsCaptcha);
|
||||
TimiException.requiredTrue(NotifyDetail.MsgType.SMS == smsDetail.getMsgType()
|
||||
&& data.getPhoneNo().equals(smsDetail.getSendTo()), "短信验证码与手机号不匹配");
|
||||
TimiException.requiredNull(userService.getByName(data.getName()), "existed user name");
|
||||
TimiException.requiredNull(userService.getByPhoneNo(data.getPhoneNo()), "existed phone number");
|
||||
if (!redisInvite.destroy(getInviteKey(code))) {
|
||||
@@ -264,10 +272,11 @@ public class GaoUserInviteServiceImplement implements GaoUserInviteService {
|
||||
.stream()
|
||||
.map(Role::getId)
|
||||
.toList();
|
||||
boolean descendant = authorizationScopeService.listManageableRole(inviterUserId, ModuleCode.GAO)
|
||||
boolean adminInviteGlobalManager = isCoreAdmin() && isGlobalManagerRole(role);
|
||||
boolean descendant = adminInviteGlobalManager || (authorizationScopeService.listManageableRole(inviterUserId, ModuleCode.GAO)
|
||||
.stream()
|
||||
.anyMatch(item -> role.getId().equals(item.getId()))
|
||||
&& !directRoleIdList.contains(role.getId());
|
||||
&& !directRoleIdList.contains(role.getId()));
|
||||
if (!descendant) {
|
||||
throw new TimiException(TimiCode.PERMISSION_ERROR, "角色不在可邀请范围内");
|
||||
}
|
||||
@@ -302,7 +311,8 @@ public class GaoUserInviteServiceImplement implements GaoUserInviteService {
|
||||
}
|
||||
|
||||
private void checkStoreScope(String userId, String storeId) {
|
||||
if (authorizationScopeService.isSystemAdmin(userId) || roleChecker.hasAny(ModuleCode.GAO, GaoRoleCode.GLOBAL_MANAGER.name())) {
|
||||
if (authorizationScopeService.isSystemAdmin(userId) || isCoreAdmin()
|
||||
|| roleChecker.hasAny(ModuleCode.GAO, GaoRoleCode.GLOBAL_MANAGER.name())) {
|
||||
return;
|
||||
}
|
||||
GaoStore userStore = gaoStoreService.getByUserId(userId);
|
||||
@@ -346,4 +356,8 @@ public class GaoUserInviteServiceImplement implements GaoUserInviteService {
|
||||
private TimiException invalidInvite() {
|
||||
return new TimiException(TimiCode.ARG_BAD, "邀请码无效或已过期");
|
||||
}
|
||||
|
||||
private boolean isCoreAdmin() {
|
||||
return roleChecker.hasAny(ModuleCode.CORE, CoreRoleCode.ADMIN.name());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,33 @@
|
||||
package com.imyeyu.api.modules.gao.vo;
|
||||
|
||||
import com.imyeyu.spring.bean.CaptchaData;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
|
||||
/// GAO 用户邀请注册请求
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-08-13
|
||||
public class GaoUserInviteRegisterRequest extends CaptchaData<GaoUserInviteRegisterData> {
|
||||
@Data
|
||||
public class GaoUserInviteRegisterRequest {
|
||||
|
||||
/// 短信通知详情 ID
|
||||
@NotBlank
|
||||
private String detailId;
|
||||
|
||||
/// 短信验证码
|
||||
@NotBlank
|
||||
@Pattern(regexp = "\\d{6}")
|
||||
private String captcha;
|
||||
|
||||
private GaoUserInviteRegisterData data;
|
||||
|
||||
/// 级联校验注册数据
|
||||
@Override
|
||||
@NotNull
|
||||
@Valid
|
||||
public GaoUserInviteRegisterData getData() {
|
||||
return super.getData();
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user