|
|
@@ -6,11 +6,13 @@ import cn.hutool.core.date.DateTime;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.fs.app.annotation.Login;
|
|
|
import com.fs.app.param.*;
|
|
|
+import com.fs.app.utils.UniVerifyUtil;
|
|
|
import com.fs.app.utils.WxUtil;
|
|
|
import com.fs.common.VerifyCodeUtil;
|
|
|
import com.fs.common.annotation.RepeatSubmit;
|
|
|
import com.fs.common.core.domain.R;
|
|
|
import com.fs.common.core.redis.RedisCache;
|
|
|
+import com.fs.common.exception.CustomException;
|
|
|
import com.fs.common.exception.ServiceException;
|
|
|
import com.fs.common.service.ISmsService;
|
|
|
import com.fs.common.utils.ServletUtils;
|
|
|
@@ -71,6 +73,9 @@ public class AppLoginController extends AppBaseController{
|
|
|
@Autowired
|
|
|
private IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private UniVerifyUtil uniVerifyUtil;
|
|
|
+
|
|
|
@ApiOperation("注册app用户")
|
|
|
@PostMapping("/register")
|
|
|
@RepeatSubmit
|
|
|
@@ -965,4 +970,133 @@ public class AppLoginController extends AppBaseController{
|
|
|
return R.ok().put("data", res);
|
|
|
}
|
|
|
|
|
|
+ @ApiOperation("UniApp一键登录(安全)")
|
|
|
+ @PostMapping("/loginByUniverify")
|
|
|
+ @Transactional
|
|
|
+ public R loginByUniverify(@RequestBody FsUserLoginParam param) {
|
|
|
+ if (StringUtils.isEmpty(param.getAccessToken()) || StringUtils.isEmpty(param.getOpenId())) {
|
|
|
+ return R.error("一键登录凭证不完整");
|
|
|
+ }
|
|
|
+ String phone;
|
|
|
+ try {
|
|
|
+ phone = uniVerifyUtil.getPhoneNumber(param.getAccessToken(), param.getOpenId());
|
|
|
+ } catch (CustomException e) {
|
|
|
+ return R.error(e.getMessage());
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("UniVerify获取手机号失败: {}", e.getMessage());
|
|
|
+ return R.error("获取手机号失败,请重试");
|
|
|
+ }
|
|
|
+ if (StringUtils.isEmpty(phone)) {
|
|
|
+ return R.error("获取手机号失败");
|
|
|
+ }
|
|
|
+ param.setPhone(phone);
|
|
|
+ return handleSecurePhoneLogin(param);
|
|
|
+ }
|
|
|
+
|
|
|
+ @ApiOperation("UniApp一键登录选择账号(安全)")
|
|
|
+ @PostMapping("/loginByUserIdUniverify")
|
|
|
+ @Transactional
|
|
|
+ public R loginByUserIdUniverify(@RequestBody FsUserLoginParam param) {
|
|
|
+ if (StringUtils.isEmpty(param.getAccessToken()) || StringUtils.isEmpty(param.getOpenId())) {
|
|
|
+ return R.error("一键登录凭证不完整");
|
|
|
+ }
|
|
|
+ String phone;
|
|
|
+ try {
|
|
|
+ phone = uniVerifyUtil.getPhoneNumber(param.getAccessToken(), param.getOpenId());
|
|
|
+ } catch (CustomException e) {
|
|
|
+ return R.error(e.getMessage());
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("UniVerify获取手机号失败: {}", e.getMessage());
|
|
|
+ return R.error("获取手机号失败,请重试");
|
|
|
+ }
|
|
|
+ if (StringUtils.isEmpty(phone)) {
|
|
|
+ return R.error("获取手机号失败");
|
|
|
+ }
|
|
|
+ param.setPhone(phone);
|
|
|
+ return handleSecurePhoneLoginByUserId(param);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * UniApp 一键登录(安全):手机号已由 uniCloud 校验,不信任客户端传入
|
|
|
+ * <ul>
|
|
|
+ * <li>无用户 → 自动注册新用户</li>
|
|
|
+ * <li>单用户 → 直接登录</li>
|
|
|
+ * <li>多用户 → 返回 users 列表,前端选择后调 /loginByUserIdUniverify</li>
|
|
|
+ * </ul>
|
|
|
+ */
|
|
|
+ private R handleSecurePhoneLogin(FsUserLoginParam param) {
|
|
|
+ String phone = param.getPhone();
|
|
|
+ List<FsUser> usersByPhone = findUsersByPhone(phone);
|
|
|
+ if (CollectionUtil.isEmpty(usersByPhone)) {
|
|
|
+ // 新用户自动注册
|
|
|
+ String appid = openProperties.getAppId();
|
|
|
+ Integer bizType = fsCoursePlaySourceConfigService.resolveBizTypeByAppId(appid);
|
|
|
+ if (bizType == null) {
|
|
|
+ bizType = appid.equals("wx7796a33a71912e32") ? 2 : 1;
|
|
|
+ }
|
|
|
+ param.setAppId(appid);
|
|
|
+ param.setBizType(bizType);
|
|
|
+ FsUser newUser = createNewUser(param);
|
|
|
+ if (StringUtils.isNotEmpty(param.getJpushId())) {
|
|
|
+ updateExistingUserJpushId(newUser, param.getJpushId());
|
|
|
+ }
|
|
|
+ updateLoginDevice(newUser.getUserId(), param.getLoginDevice(), param.getSource());
|
|
|
+ return generateTokenAndReturn(newUser);
|
|
|
+ }
|
|
|
+ if (usersByPhone.size() == 1) {
|
|
|
+ FsUser user = usersByPhone.get(0);
|
|
|
+ // 历史用户首次一键登录:手机号还是明文,加密后落库
|
|
|
+ if (user.getUnionId() == null) {
|
|
|
+ if (user.getPhone() != null && user.getPhone().length() <= 11) {
|
|
|
+ FsUser fsUser = new FsUser();
|
|
|
+ fsUser.setUserId(user.getUserId());
|
|
|
+ fsUser.setPhone(encryptPhone(phone));
|
|
|
+ userMapper.updateFsUser(fsUser);
|
|
|
+ }
|
|
|
+ return R.ok().put("isNew", true).put("phone", encryptPhone(phone));
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotEmpty(param.getJpushId())) {
|
|
|
+ updateExistingUserJpushId(user, param.getJpushId());
|
|
|
+ }
|
|
|
+ updateLoginDevice(user.getUserId(), param.getLoginDevice(), param.getSource());
|
|
|
+ return generateTokenAndReturn(user);
|
|
|
+ }
|
|
|
+ // 多账号场景,脱敏后返回让前端选择
|
|
|
+ for (FsUser fsUser : usersByPhone) {
|
|
|
+ fsUser.setPhone("***********");
|
|
|
+ }
|
|
|
+ return R.ok().put("users", usersByPhone);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 多账号场景下按 userId 登录,手机号已由 uniCloud 校验
|
|
|
+ */
|
|
|
+ private R handleSecurePhoneLoginByUserId(FsUserLoginParam param) {
|
|
|
+ List<FsUser> usersByPhone = findUsersByPhone(param.getPhone());
|
|
|
+ if (CollectionUtil.isEmpty(usersByPhone)) {
|
|
|
+ return R.error("账号不存在,请先注册账号");
|
|
|
+ }
|
|
|
+ if (usersByPhone.size() == 1) {
|
|
|
+ FsUser user = usersByPhone.get(0);
|
|
|
+ if (StringUtils.isNotEmpty(param.getJpushId())) {
|
|
|
+ updateExistingUserJpushId(user, param.getJpushId());
|
|
|
+ }
|
|
|
+ updateLoginDevice(user.getUserId(), param.getLoginDevice(), param.getSource());
|
|
|
+ return generateTokenAndReturn(user);
|
|
|
+ }
|
|
|
+ if (param.getUserId() == null) {
|
|
|
+ return R.error("请选择登录账号");
|
|
|
+ }
|
|
|
+ for (FsUser fsUser : usersByPhone) {
|
|
|
+ if (fsUser.getUserId().equals(param.getUserId())) {
|
|
|
+ if (StringUtils.isNotEmpty(param.getJpushId())) {
|
|
|
+ updateExistingUserJpushId(fsUser, param.getJpushId());
|
|
|
+ }
|
|
|
+ updateLoginDevice(fsUser.getUserId(), param.getLoginDevice(), param.getSource());
|
|
|
+ return generateTokenAndReturn(fsUser);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return R.error("账号不匹配,请检查账号");
|
|
|
+ }
|
|
|
+
|
|
|
}
|