|
|
@@ -46,6 +46,7 @@ import com.ruoyi.system.utils.JwtUtil;
|
|
|
import com.ruoyi.system.utils.MobileSMS;
|
|
|
import com.ruoyi.app.user.dto.OAuthBindDto;
|
|
|
import com.ruoyi.app.user.dto.OAuthLoginDto;
|
|
|
+import com.ruoyi.app.utils.oauth.LineOAuthProperties;
|
|
|
import com.ruoyi.app.utils.oauth.OAuthVerifyService;
|
|
|
import com.ruoyi.system.mapper.InfoUserOauthMapper;
|
|
|
|
|
|
@@ -108,6 +109,10 @@ public class InfoUserController extends BaseController {
|
|
|
@Autowired
|
|
|
private OAuthVerifyService oauthVerifyService;
|
|
|
@Autowired
|
|
|
+ private LineOAuthProperties lineOAuthProperties;
|
|
|
+ @Autowired
|
|
|
+ private BusinessPhoneService businessPhoneService;
|
|
|
+ @Autowired
|
|
|
private MerchantStoreAccessService merchantStoreAccessService;
|
|
|
@Autowired
|
|
|
private MerchantTokenSessionService merchantTokenSessionService;
|
|
|
@@ -316,6 +321,7 @@ public class InfoUserController extends BaseController {
|
|
|
* @return
|
|
|
*/
|
|
|
public AjaxResult createQsUser(UserDTO userDTO) {
|
|
|
+ businessPhoneService.ensureUnique(userDTO.getTelPhone(), null);
|
|
|
InfoUser user = new InfoUser();
|
|
|
UUIDUtil uuid = new UUIDUtil();
|
|
|
user.setUserName(userDTO.getUserName());
|
|
|
@@ -371,6 +377,7 @@ public class InfoUserController extends BaseController {
|
|
|
* @return
|
|
|
*/
|
|
|
public AjaxResult createShUser(UserDTO userDTO) {
|
|
|
+ businessPhoneService.ensureUnique(userDTO.getTelPhone(), null);
|
|
|
InfoUser user = new InfoUser();
|
|
|
UUIDUtil uuid = new UUIDUtil();
|
|
|
user.setUserName(userDTO.getUserName());
|
|
|
@@ -446,6 +453,7 @@ public class InfoUserController extends BaseController {
|
|
|
LoginUserDto userDto = new LoginUserDto();
|
|
|
userDto.setUserId(user.getUserId());
|
|
|
userDto.setUserName(user.getUserName());
|
|
|
+ userDto.setProvider("phone");
|
|
|
fillLoginUserInfo(userDto);
|
|
|
String token = JwtUtil.setToken(tokenKey, userDto);
|
|
|
return success(MessageUtils.message("no.user.login.success"), merchantLoginView(user), token);
|
|
|
@@ -504,6 +512,7 @@ public class InfoUserController extends BaseController {
|
|
|
LoginUserDto userDto = new LoginUserDto();
|
|
|
userDto.setUserId(user.getUserId());
|
|
|
userDto.setUserName(user.getUserName());
|
|
|
+ userDto.setProvider("phone");
|
|
|
fillLoginUserInfo(userDto);
|
|
|
String token = JwtUtil.setToken(CacheConstants.QS_TOKEN_KEY, userDto);
|
|
|
return success(MessageUtils.message("no.user.login.success"), user, token);
|
|
|
@@ -667,6 +676,9 @@ public class InfoUserController extends BaseController {
|
|
|
if (user == null) {
|
|
|
return error(MessageUtils.message("no.user.not.exist"));
|
|
|
} else {
|
|
|
+ if (businessPhoneService.isBusinessUserType(user.getUserType())) {
|
|
|
+ businessPhoneService.ensureUnique(userDTO.getTelPhone(), user.getUserId());
|
|
|
+ }
|
|
|
InfoUser infoUser = new InfoUser();
|
|
|
infoUser.setUserId(user.getUserId());
|
|
|
infoUser.setTelPhone(userDTO.getTelPhone());
|
|
|
@@ -735,10 +747,13 @@ public class InfoUserController extends BaseController {
|
|
|
public AjaxResult setuser(@RequestHeader String token, @RequestBody InfoUser infoUser) {
|
|
|
JwtUtil jwtUtil = new JwtUtil();
|
|
|
String id = jwtUtil.getusid(token);
|
|
|
+ InfoUser current = infoUserService.getById(id);
|
|
|
+ if (current != null && businessPhoneService.isBusinessUserType(current.getUserType())) {
|
|
|
+ businessPhoneService.ensureUnique(infoUser.getTelPhone(), current.getUserId());
|
|
|
+ }
|
|
|
normalizeDeliveryType(infoUser);
|
|
|
InfoUser user = new InfoUser();
|
|
|
user.setUserId(Long.valueOf(id));
|
|
|
- user.setUserType(infoUser.getUserType());
|
|
|
user.setCid(infoUser.getCid());
|
|
|
user.setCidType(infoUser.getCidType());
|
|
|
user.setDeviceToken(infoUser.getDeviceToken());
|
|
|
@@ -747,7 +762,6 @@ public class InfoUserController extends BaseController {
|
|
|
user.setAvatar(infoUser.getAvatar());
|
|
|
user.setEmail(infoUser.getEmail());
|
|
|
user.setSex(infoUser.getSex());
|
|
|
- user.setStatus(infoUser.getStatus());
|
|
|
user.setThiscode(infoUser.getThiscode());
|
|
|
user.setAnnex(infoUser.getAnnex());
|
|
|
user.setTelPhone(infoUser.getTelPhone());
|
|
|
@@ -898,6 +912,8 @@ public class InfoUserController extends BaseController {
|
|
|
LoginUserDto userDto = new LoginUserDto();
|
|
|
userDto.setUserId(user.getUserId());
|
|
|
userDto.setUserName(user.getUserName());
|
|
|
+ Object provider = JwtUtil.verifyToken(token).get("provider");
|
|
|
+ userDto.setProvider(provider == null || "null".equals(provider) ? "phone" : String.valueOf(provider));
|
|
|
fillLoginUserInfo(userDto);
|
|
|
String wtoken = JwtUtil.setToken(CacheConstants.USER_TOKEN_KEY, userDto);
|
|
|
return success(MessageUtils.message("no.user.token.success"), wtoken);
|
|
|
@@ -966,6 +982,7 @@ public class InfoUserController extends BaseController {
|
|
|
LoginUserDto userDto = new LoginUserDto();
|
|
|
userDto.setUserId(inus.getUserId());
|
|
|
userDto.setUserName(inus.getPhone());
|
|
|
+ userDto.setProvider("phone");
|
|
|
fillLoginUserInfo(userDto);
|
|
|
String token = JwtUtil.setToken(CacheConstants.USER_TOKEN_KEY, userDto);
|
|
|
return success(MessageUtils.message("no.user.login.success"), inus, token);
|
|
|
@@ -1010,6 +1027,7 @@ public class InfoUserController extends BaseController {
|
|
|
LoginUserDto userDto = new LoginUserDto();
|
|
|
userDto.setUserId(user.getUserId());
|
|
|
userDto.setUserName(user.getPhone());
|
|
|
+ userDto.setProvider("phone");
|
|
|
fillLoginUserInfo(userDto);
|
|
|
String token = JwtUtil.setToken(CacheConstants.USER_TOKEN_KEY, userDto);
|
|
|
return success(MessageUtils.message("no.user.login.success"), user, token);
|
|
|
@@ -1026,6 +1044,7 @@ public class InfoUserController extends BaseController {
|
|
|
if (dto == null || dto.getProvider() == null || dto.getProvider().isEmpty()) {
|
|
|
return error(MessageUtils.message("no.oauth.provider.blank"));
|
|
|
}
|
|
|
+ LineOAuthProperties.ResolvedChannel lineChannel = resolveLineChannel(dto.getProvider());
|
|
|
log.info("[OAuth] oauthLogin provider={}", dto.getProvider());
|
|
|
String providerUid = oauthVerifyService.verify(dto.getProvider(), dto.getCredential());
|
|
|
|
|
|
@@ -1036,7 +1055,7 @@ public class InfoUserController extends BaseController {
|
|
|
.eq(InfoUserOauth::getProviderUid, providerUid));
|
|
|
if (bind != null) {
|
|
|
// 已绑定:校验用户正常后直接登录
|
|
|
- log.info("[OAuth] 已绑定 provider={}, providerUid={}, userId={}", dto.getProvider(), providerUid, bind.getUserId());
|
|
|
+ log.info("[OAuth] 已绑定 provider={}, userId={}", dto.getProvider(), bind.getUserId());
|
|
|
QueryWrapper<InfoUser> q = new QueryWrapper<>();
|
|
|
q.eq("user_id", bind.getUserId()).eq("status", 0).eq("del_flag", "0");
|
|
|
InfoUser u = infoUserService.getOne(q);
|
|
|
@@ -1044,6 +1063,9 @@ public class InfoUserController extends BaseController {
|
|
|
log.warn("[OAuth] 已绑定但账号已停用 userId={}", bind.getUserId());
|
|
|
return error(MessageUtils.message("no.user.stop"));
|
|
|
}
|
|
|
+ if (lineChannel != null && !canLineLogin(lineChannel, u)) {
|
|
|
+ return error(MessageUtils.message("no.user.stop"));
|
|
|
+ }
|
|
|
u.setCid(dto.getCid());
|
|
|
u.setCidType(dto.getCidType());
|
|
|
u.setDeviceToken(dto.getDeviceToken());
|
|
|
@@ -1053,7 +1075,7 @@ public class InfoUserController extends BaseController {
|
|
|
}
|
|
|
|
|
|
// 未绑定:缓存 {provider, providerUid},返回 needPhone + tempKey
|
|
|
- log.info("[OAuth] 未绑定,返回 needPhone provider={}, providerUid={}", dto.getProvider(), providerUid);
|
|
|
+ log.info("[OAuth] 未绑定,返回 needPhone provider={}", dto.getProvider());
|
|
|
String tempKey = UUID.randomUUID().toString().replace("-", "");
|
|
|
redisCache.setCacheObject(OAUTH_TEMP_PREFIX + tempKey,
|
|
|
dto.getProvider() + "@" + providerUid, 5, TimeUnit.MINUTES);
|
|
|
@@ -1067,21 +1089,27 @@ public class InfoUserController extends BaseController {
|
|
|
* 三方登录第二步:手机号 + 短信验证 → 已注册关联 / 未注册新建 → 写绑定 → 签 token。
|
|
|
*/
|
|
|
@Anonymous
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
@PostMapping("/oauthBindPhone")
|
|
|
public AjaxResult oauthBindPhone(@RequestBody OAuthBindDto dto) {
|
|
|
if (dto == null || dto.getTempKey() == null || dto.getTempKey().isEmpty()) {
|
|
|
log.warn("[OAuth] oauthBindPhone 缺 tempKey");
|
|
|
return error(MessageUtils.message("no.oauth.tempkey.missing"));
|
|
|
}
|
|
|
- String cached = redisCache.getCacheObject(OAUTH_TEMP_PREFIX + dto.getTempKey());
|
|
|
- if (cached == null) {
|
|
|
- log.warn("[OAuth] tempKey 已过期/不存在 tempKey={}", dto.getTempKey());
|
|
|
+ String tempCacheKey = OAUTH_TEMP_PREFIX + dto.getTempKey();
|
|
|
+ String cached = redisCache.getCacheObject(tempCacheKey);
|
|
|
+ if (cached == null || !redisCache.deleteObject(tempCacheKey)) {
|
|
|
+ log.warn("[OAuth] tempKey 已过期/不存在");
|
|
|
return error(MessageUtils.message("no.oauth.tempkey.expired"));
|
|
|
}
|
|
|
int at = cached.indexOf('@');
|
|
|
+ if (at <= 0 || at == cached.length() - 1) {
|
|
|
+ return error(MessageUtils.message("no.oauth.tempkey.expired"));
|
|
|
+ }
|
|
|
String provider = cached.substring(0, at);
|
|
|
String providerUid = cached.substring(at + 1);
|
|
|
- log.info("[OAuth] 绑定流程 provider={}, providerUid={}", provider, providerUid);
|
|
|
+ LineOAuthProperties.ResolvedChannel lineChannel = resolveLineChannel(provider);
|
|
|
+ log.info("[OAuth] 绑定流程 provider={}", provider);
|
|
|
|
|
|
// 容错:若期间已被绑定,直接登录
|
|
|
InfoUserOauth exist = infoUserOauthMapper.selectOne(
|
|
|
@@ -1091,11 +1119,17 @@ public class InfoUserController extends BaseController {
|
|
|
if (exist != null) {
|
|
|
log.info("[OAuth] 绑定期间已被绑定,直接登录 userId={}", exist.getUserId());
|
|
|
InfoUser u = infoUserService.getById(exist.getUserId());
|
|
|
+ if (lineChannel != null && !canLineLogin(lineChannel, u)) {
|
|
|
+ return error(MessageUtils.message("no.user.stop"));
|
|
|
+ }
|
|
|
return issueOauthToken(u, provider);
|
|
|
}
|
|
|
|
|
|
// 验短信(复用 lodeing 逻辑:redis code 或万能码 8888)
|
|
|
String phone = dto.getPhone();
|
|
|
+ if (phone == null || phone.isBlank()) {
|
|
|
+ return error(MessageUtils.message("no.oauth.phone.blank"));
|
|
|
+ }
|
|
|
String xcode = redisCache.getCacheObject(phone.trim().replaceAll("\\+", ""));
|
|
|
boolean codeOk = (xcode != null && xcode.equals(dto.getCode())) || "8888".equals(dto.getCode());
|
|
|
if (!codeOk) {
|
|
|
@@ -1103,14 +1137,26 @@ public class InfoUserController extends BaseController {
|
|
|
return error(MessageUtils.message("no.user.jcaptcha.error"));
|
|
|
}
|
|
|
|
|
|
- // 查/建用户(手机号始终为主键)
|
|
|
- InfoUser user = infoUserService.getuser(phone);
|
|
|
+ InfoUser user;
|
|
|
+ if (lineChannel != null) {
|
|
|
+ user = findLineBindingUser(lineChannel, phone);
|
|
|
+ } else {
|
|
|
+ user = infoUserService.getuser(phone);
|
|
|
+ }
|
|
|
+ if (lineChannel != null && !lineChannel.allowCreate()) {
|
|
|
+ if (user == null) {
|
|
|
+ return error(MessageUtils.message("no.user.not.exist"));
|
|
|
+ }
|
|
|
+ if (!canLineLogin(lineChannel, user)) {
|
|
|
+ return error(MessageUtils.message("no.user.stop"));
|
|
|
+ }
|
|
|
+ }
|
|
|
if (user != null && !"0".equals(user.getStatus())) {
|
|
|
// 停用账号不允许绑定三方(与 lodeing 一致,防止绕过停用)
|
|
|
log.warn("[OAuth] 账号已停用 phone={}", maskPhone(phone));
|
|
|
return error(MessageUtils.message("no.user.stop"));
|
|
|
}
|
|
|
- if (user == null) {
|
|
|
+ if (user == null && (lineChannel == null || lineChannel.allowCreate())) {
|
|
|
// 新建:昵称=手机号(与 createUser 一致)
|
|
|
InfoUser info = new InfoUser();
|
|
|
info.setPhone(phone);
|
|
|
@@ -1121,8 +1167,14 @@ public class InfoUserController extends BaseController {
|
|
|
info.setVoIPToken(dto.getVoIPToken());
|
|
|
info.setUserType("0");
|
|
|
info.setMycode(new UUIDUtil().get8UUID());
|
|
|
- infoUserService.saveOrUpdate(info);
|
|
|
- user = infoUserService.getuser(phone);
|
|
|
+ if (!infoUserService.saveOrUpdate(info)) {
|
|
|
+ throw new ServiceException(MessageUtils.message("no.system.error"));
|
|
|
+ }
|
|
|
+ user = lineChannel == null
|
|
|
+ ? infoUserService.getuser(phone) : findLineBindingUser(lineChannel, phone);
|
|
|
+ if (user == null) {
|
|
|
+ return error(MessageUtils.message("no.user.not.exist"));
|
|
|
+ }
|
|
|
createUserWallet(user.getUserId());
|
|
|
log.info("[OAuth] 新建账号 userId={}", user.getUserId());
|
|
|
} else {
|
|
|
@@ -1130,7 +1182,9 @@ public class InfoUserController extends BaseController {
|
|
|
user.setCidType(dto.getCidType());
|
|
|
user.setDeviceToken(dto.getDeviceToken());
|
|
|
user.setVoIPToken(dto.getVoIPToken());
|
|
|
- infoUserService.saveOrUpdate(user);
|
|
|
+ if (!infoUserService.saveOrUpdate(user)) {
|
|
|
+ throw new ServiceException(MessageUtils.message("no.system.error"));
|
|
|
+ }
|
|
|
log.info("[OAuth] 关联已有账号 userId={}", user.getUserId());
|
|
|
}
|
|
|
|
|
|
@@ -1140,10 +1194,11 @@ public class InfoUserController extends BaseController {
|
|
|
bind.setProvider(provider);
|
|
|
bind.setProviderUid(providerUid);
|
|
|
bind.setCreateTime(new Date());
|
|
|
- infoUserOauthMapper.insert(bind);
|
|
|
- log.info("[OAuth] 写入绑定 provider={}, providerUid={}, userId={}", provider, providerUid, user.getUserId());
|
|
|
+ if (infoUserOauthMapper.insert(bind) != 1) {
|
|
|
+ throw new ServiceException(MessageUtils.message("no.system.error"));
|
|
|
+ }
|
|
|
+ log.info("[OAuth] 写入绑定 provider={}, userId={}", provider, user.getUserId());
|
|
|
|
|
|
- redisCache.deleteObject(OAUTH_TEMP_PREFIX + dto.getTempKey());
|
|
|
return issueOauthToken(user, provider);
|
|
|
}
|
|
|
|
|
|
@@ -1160,14 +1215,58 @@ public class InfoUserController extends BaseController {
|
|
|
if (user == null) {
|
|
|
return error(MessageUtils.message("no.user.not.exist"));
|
|
|
}
|
|
|
- redisCache.deleteKeys(CacheConstants.USER_TOKEN_KEY + user.getUserId() + ":" + "*");
|
|
|
+ if (!"0".equals(user.getStatus()) || !"0".equals(user.getDelFlag())) {
|
|
|
+ return error(MessageUtils.message("no.user.stop"));
|
|
|
+ }
|
|
|
+ LineOAuthProperties.ResolvedChannel lineChannel = resolveLineChannel(provider);
|
|
|
+ if (lineChannel != null && !canLineLogin(lineChannel, user)) {
|
|
|
+ return error(MessageUtils.message("no.user.stop"));
|
|
|
+ }
|
|
|
+ String tokenKey = lineChannel == null ? CacheConstants.USER_TOKEN_KEY : lineChannel.tokenKey();
|
|
|
+ redisCache.deleteKeys(tokenKey + user.getUserId() + ":*");
|
|
|
LoginUserDto dto = new LoginUserDto();
|
|
|
dto.setUserId(user.getUserId());
|
|
|
- dto.setUserName(user.getPhone());
|
|
|
+ dto.setUserName(lineChannel == null || lineChannel.allowCreate()
|
|
|
+ ? user.getPhone() : user.getUserName());
|
|
|
dto.setProvider(provider);
|
|
|
fillLoginUserInfo(dto);
|
|
|
- String token = JwtUtil.setToken(CacheConstants.USER_TOKEN_KEY, dto);
|
|
|
- return success(MessageUtils.message("no.user.login.success"), user, token);
|
|
|
+ String token = JwtUtil.setToken(tokenKey, dto);
|
|
|
+ Object loginUser = lineChannel != null
|
|
|
+ && "line_merchant".equals(lineChannel.provider()) ? merchantLoginView(user) : user;
|
|
|
+ return success(MessageUtils.message("no.user.login.success"), loginUser, token);
|
|
|
+ }
|
|
|
+
|
|
|
+ private LineOAuthProperties.ResolvedChannel resolveLineChannel(String provider) {
|
|
|
+ return provider != null && provider.startsWith("line_")
|
|
|
+ ? lineOAuthProperties.requireChannel(provider) : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean canLineLogin(LineOAuthProperties.ResolvedChannel channel, InfoUser user) {
|
|
|
+ if (user == null || !"0".equals(user.getStatus()) || !"0".equals(user.getDelFlag())
|
|
|
+ || !channel.userTypes().contains(user.getUserType())) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (!MerchantAccountConstants.SUBACCOUNT_USER_TYPE.equals(user.getUserType())) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (!MerchantAccountConstants.STATUS_ENABLED.equals(user.getSubaccountStatus())) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ merchantStoreAccessService.resolve(user.getUserId());
|
|
|
+ return true;
|
|
|
+ } catch (ServiceException exception) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private InfoUser findLineBindingUser(LineOAuthProperties.ResolvedChannel channel, String phone) {
|
|
|
+ LambdaQueryWrapper<InfoUser> query = new LambdaQueryWrapper<InfoUser>()
|
|
|
+ .eq(channel.allowCreate(), InfoUser::getPhone, phone)
|
|
|
+ .eq(!channel.allowCreate(), InfoUser::getTelPhone, phone)
|
|
|
+ .eq(InfoUser::getDelFlag, "0")
|
|
|
+ .in(InfoUser::getUserType, channel.userTypes());
|
|
|
+ return infoUserService.getOne(query);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -1246,6 +1345,8 @@ public class InfoUserController extends BaseController {
|
|
|
normalizeDeliveryType(infoUser);
|
|
|
if (infoUserService.getinfouserName(infoUser.getUserName()) != null) {
|
|
|
return error(MessageUtils.message("no.user.add") + infoUser.getUserName() + MessageUtils.message("no.user.login.exist"));
|
|
|
+ } else if (businessPhoneService.isBusinessUserType(infoUser.getUserType())) {
|
|
|
+ businessPhoneService.ensureUnique(infoUser.getTelPhone(), null);
|
|
|
} else if (infoUserService.getinfoPhone(infoUser.getPhone()) != null) {
|
|
|
return error(MessageUtils.message("no.user.add") + infoUser.getPhone() + MessageUtils.message("no.user.mobile.exist"));
|
|
|
}
|
|
|
@@ -1276,6 +1377,11 @@ public class InfoUserController extends BaseController {
|
|
|
return error(MessageUtils.message("no.user.audit.reject.reason.required"));
|
|
|
}
|
|
|
normalizeDeliveryType(infoUser);
|
|
|
+ String effectiveUserType = infoUser.getUserType() != null
|
|
|
+ ? infoUser.getUserType() : existing == null ? null : existing.getUserType();
|
|
|
+ if (businessPhoneService.isBusinessUserType(effectiveUserType)) {
|
|
|
+ businessPhoneService.ensureUnique(infoUser.getTelPhone(), infoUser.getUserId());
|
|
|
+ }
|
|
|
return toAjax(infoUserService.updateInfoUser(infoUser));
|
|
|
}
|
|
|
|