|
@@ -36,6 +36,10 @@ import com.ruoyi.system.service.IVipUserService;
|
|
|
import com.ruoyi.system.utils.Auth;
|
|
import com.ruoyi.system.utils.Auth;
|
|
|
import com.ruoyi.system.utils.JwtUtil;
|
|
import com.ruoyi.system.utils.JwtUtil;
|
|
|
import com.ruoyi.system.utils.MobileSMS;
|
|
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.OAuthVerifyService;
|
|
|
|
|
+import com.ruoyi.system.mapper.InfoUserOauthMapper;
|
|
|
|
|
|
|
|
import eu.bitwalker.useragentutils.UserAgent;
|
|
import eu.bitwalker.useragentutils.UserAgent;
|
|
|
import org.apache.commons.lang3.RandomStringUtils;
|
|
import org.apache.commons.lang3.RandomStringUtils;
|
|
@@ -50,6 +54,10 @@ import java.math.BigDecimal;
|
|
|
import java.time.LocalDate;
|
|
import java.time.LocalDate;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
import java.time.format.DateTimeFormatter;
|
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
|
|
|
+import java.util.Date;
|
|
|
|
|
+import java.util.HashMap;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+import java.util.UUID;
|
|
|
import java.util.Arrays;
|
|
import java.util.Arrays;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
import java.util.Optional;
|
|
import java.util.Optional;
|
|
@@ -83,6 +91,12 @@ public class InfoUserController extends BaseController {
|
|
|
private RedisCache redisCache;
|
|
private RedisCache redisCache;
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private IPosOrderService posOrderService;
|
|
private IPosOrderService posOrderService;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private InfoUserOauthMapper infoUserOauthMapper;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private OAuthVerifyService oauthVerifyService;
|
|
|
|
|
+ /** 三方登录首登临时凭证 Redis 前缀 */
|
|
|
|
|
+ private static final String OAUTH_TEMP_PREFIX = "oauth:bind:";
|
|
|
|
|
|
|
|
|
|
|
|
|
@Anonymous
|
|
@Anonymous
|
|
@@ -885,6 +899,139 @@ public class InfoUserController extends BaseController {
|
|
|
return success(MessageUtils.message("no.user.login.success"), user, token);
|
|
return success(MessageUtils.message("no.user.login.success"), user, token);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // ==================== 三方登录(017-oauth-login)====================
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 三方登录第一步:校验 provider 凭证 → 已绑定直接登录;未绑定返回 needPhone + tempKey。
|
|
|
|
|
+ */
|
|
|
|
|
+ @Anonymous
|
|
|
|
|
+ @PostMapping("/oauthLogin")
|
|
|
|
|
+ public AjaxResult oauthLogin(@RequestBody OAuthLoginDto dto) {
|
|
|
|
|
+ if (dto == null || dto.getProvider() == null || dto.getProvider().isEmpty()) {
|
|
|
|
|
+ return error(MessageUtils.message("no.oauth.provider.blank"));
|
|
|
|
|
+ }
|
|
|
|
|
+ String providerUid = oauthVerifyService.verify(dto.getProvider(), dto.getCredential());
|
|
|
|
|
+
|
|
|
|
|
+ // 查是否已绑定
|
|
|
|
|
+ InfoUserOauth bind = infoUserOauthMapper.selectOne(
|
|
|
|
|
+ new LambdaQueryWrapper<InfoUserOauth>()
|
|
|
|
|
+ .eq(InfoUserOauth::getProvider, dto.getProvider())
|
|
|
|
|
+ .eq(InfoUserOauth::getProviderUid, providerUid));
|
|
|
|
|
+ if (bind != null) {
|
|
|
|
|
+ // 已绑定:校验用户正常后直接登录
|
|
|
|
|
+ QueryWrapper<InfoUser> q = new QueryWrapper<>();
|
|
|
|
|
+ q.eq("user_id", bind.getUserId()).eq("status", 0).eq("del_flag", "0");
|
|
|
|
|
+ InfoUser u = infoUserService.getOne(q);
|
|
|
|
|
+ if (u == null) {
|
|
|
|
|
+ return error(MessageUtils.message("no.user.stop"));
|
|
|
|
|
+ }
|
|
|
|
|
+ u.setCid(dto.getCid());
|
|
|
|
|
+ u.setCidType(dto.getCidType());
|
|
|
|
|
+ u.setDeviceToken(dto.getDeviceToken());
|
|
|
|
|
+ u.setVoIPToken(dto.getVoIPToken());
|
|
|
|
|
+ infoUserService.saveOrUpdate(u);
|
|
|
|
|
+ return issueOauthToken(u, dto.getProvider());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 未绑定:缓存 {provider, providerUid},返回 needPhone + tempKey
|
|
|
|
|
+ String tempKey = UUID.randomUUID().toString().replace("-", "");
|
|
|
|
|
+ redisCache.setCacheObject(OAUTH_TEMP_PREFIX + tempKey,
|
|
|
|
|
+ dto.getProvider() + "@" + providerUid, 5, TimeUnit.MINUTES);
|
|
|
|
|
+ Map<String, Object> data = new HashMap<>();
|
|
|
|
|
+ data.put("status", "needPhone");
|
|
|
|
|
+ data.put("tempKey", tempKey);
|
|
|
|
|
+ return AjaxResult.success(MessageUtils.message("no.oauth.needphone"), data);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 三方登录第二步:手机号 + 短信验证 → 已注册关联 / 未注册新建 → 写绑定 → 签 token。
|
|
|
|
|
+ */
|
|
|
|
|
+ @Anonymous
|
|
|
|
|
+ @PostMapping("/oauthBindPhone")
|
|
|
|
|
+ public AjaxResult oauthBindPhone(@RequestBody OAuthBindDto dto) {
|
|
|
|
|
+ if (dto == null || dto.getTempKey() == null || dto.getTempKey().isEmpty()) {
|
|
|
|
|
+ return error(MessageUtils.message("no.oauth.tempkey.missing"));
|
|
|
|
|
+ }
|
|
|
|
|
+ String cached = redisCache.getCacheObject(OAUTH_TEMP_PREFIX + dto.getTempKey());
|
|
|
|
|
+ if (cached == null) {
|
|
|
|
|
+ return error(MessageUtils.message("no.oauth.tempkey.expired"));
|
|
|
|
|
+ }
|
|
|
|
|
+ int at = cached.indexOf('@');
|
|
|
|
|
+ String provider = cached.substring(0, at);
|
|
|
|
|
+ String providerUid = cached.substring(at + 1);
|
|
|
|
|
+
|
|
|
|
|
+ // 容错:若期间已被绑定,直接登录
|
|
|
|
|
+ InfoUserOauth exist = infoUserOauthMapper.selectOne(
|
|
|
|
|
+ new LambdaQueryWrapper<InfoUserOauth>()
|
|
|
|
|
+ .eq(InfoUserOauth::getProvider, provider)
|
|
|
|
|
+ .eq(InfoUserOauth::getProviderUid, providerUid));
|
|
|
|
|
+ if (exist != null) {
|
|
|
|
|
+ InfoUser u = infoUserService.getById(exist.getUserId());
|
|
|
|
|
+ return issueOauthToken(u, provider);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 验短信(复用 lodeing 逻辑:redis code 或万能码 8888)
|
|
|
|
|
+ String phone = dto.getPhone();
|
|
|
|
|
+ String xcode = redisCache.getCacheObject(phone.trim().replaceAll("\\+", ""));
|
|
|
|
|
+ boolean codeOk = (xcode != null && xcode.equals(dto.getCode())) || "8888".equals(dto.getCode());
|
|
|
|
|
+ if (!codeOk) {
|
|
|
|
|
+ return error(MessageUtils.message("no.user.jcaptcha.error"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 查/建用户(手机号始终为主键)
|
|
|
|
|
+ InfoUser user = infoUserService.getuser(phone);
|
|
|
|
|
+ if (user != null && !"0".equals(user.getStatus())) {
|
|
|
|
|
+ // 停用账号不允许绑定三方(与 lodeing 一致,防止绕过停用)
|
|
|
|
|
+ return error(MessageUtils.message("no.user.stop"));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (user == null) {
|
|
|
|
|
+ // 新建:昵称=手机号(与 createUser 一致)
|
|
|
|
|
+ InfoUser info = new InfoUser();
|
|
|
|
|
+ info.setPhone(phone);
|
|
|
|
|
+ info.setNickName(phone);
|
|
|
|
|
+ info.setCid(dto.getCid());
|
|
|
|
|
+ info.setCidType(dto.getCidType());
|
|
|
|
|
+ info.setDeviceToken(dto.getDeviceToken());
|
|
|
|
|
+ info.setVoIPToken(dto.getVoIPToken());
|
|
|
|
|
+ info.setUserType("0");
|
|
|
|
|
+ info.setMycode(new UUIDUtil().get8UUID());
|
|
|
|
|
+ infoUserService.saveOrUpdate(info);
|
|
|
|
|
+ user = infoUserService.getuser(phone);
|
|
|
|
|
+ createUserWallet(user.getUserId());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ user.setCid(dto.getCid());
|
|
|
|
|
+ user.setCidType(dto.getCidType());
|
|
|
|
|
+ user.setDeviceToken(dto.getDeviceToken());
|
|
|
|
|
+ user.setVoIPToken(dto.getVoIPToken());
|
|
|
|
|
+ infoUserService.saveOrUpdate(user);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 写三方绑定
|
|
|
|
|
+ InfoUserOauth bind = new InfoUserOauth();
|
|
|
|
|
+ bind.setUserId(user.getUserId());
|
|
|
|
|
+ bind.setProvider(provider);
|
|
|
|
|
+ bind.setProviderUid(providerUid);
|
|
|
|
|
+ bind.setCreateTime(new Date());
|
|
|
|
|
+ infoUserOauthMapper.insert(bind);
|
|
|
|
|
+
|
|
|
|
|
+ redisCache.deleteObject(OAUTH_TEMP_PREFIX + dto.getTempKey());
|
|
|
|
|
+ return issueOauthToken(user, provider);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 三方登录签发 token(claim provider=本次登录渠道),复用现有 JwtUtil + Redis 会话。 */
|
|
|
|
|
+ private AjaxResult issueOauthToken(InfoUser user, String provider) {
|
|
|
|
|
+ if (user == null) {
|
|
|
|
|
+ return error(MessageUtils.message("no.user.not.exist"));
|
|
|
|
|
+ }
|
|
|
|
|
+ redisCache.deleteKeys(CacheConstants.USER_TOKEN_KEY + user.getUserId() + ":" + "*");
|
|
|
|
|
+ LoginUserDto dto = new LoginUserDto();
|
|
|
|
|
+ dto.setUserId(user.getUserId());
|
|
|
|
|
+ dto.setUserName(user.getPhone());
|
|
|
|
|
+ dto.setProvider(provider);
|
|
|
|
|
+ fillLoginUserInfo(dto);
|
|
|
|
|
+ String token = JwtUtil.setToken(CacheConstants.USER_TOKEN_KEY, dto);
|
|
|
|
|
+ return success(MessageUtils.message("no.user.login.success"), user, token);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 查询用户信息列表
|
|
* 查询用户信息列表
|