shikeyin
2024-01-11 65da8373531677b1c37a98f53eaa30c892f35e5a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
package com.ishop.mobile.api;
 
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.iplatform.base.ArgumentsConstants;
import com.iplatform.base.Constants;
import com.iplatform.base.PlatformRuntimeException;
import com.iplatform.base.SecuritySpi;
import com.iplatform.base.WechatConstants;
import com.iplatform.base.captcha.BlockPuzzleCaptchaProvider;
import com.iplatform.base.captcha.JigsawResult;
import com.iplatform.base.exception.LoginException;
import com.iplatform.base.pojo.CaptchaParam;
import com.iplatform.base.pojo.RequestLogin;
import com.iplatform.model.po.S_user_core;
import com.ishop.merchant.util.VoUtils;
import com.ishop.mobile.BaseApi;
import com.ishop.mobile.pojo.LoginParam;
import com.ishop.mobile.pojo.SmsCodeParam;
import com.ishop.mobile.pojo.WechatLoginRequest;
import com.ishop.mobile.support.WechatEngine;
import com.ishop.mobile.util.LoginUtils;
import com.ishop.mobile.util.WechatUtils;
import com.ishop.model.po.EbUser;
import com.ishop.model.po.EbUserToken;
import com.ishop.model.request.RegisterThirdUserRequest;
import com.ishop.model.vo.LoginConfigVo;
import com.ishop.model.vo.LoginInfoVo;
import com.ishop.model.vo.WechatMiniAuthorizeVo;
import com.ishop.model.wechat.WeChatAuthorizeLoginUserInfoVo;
import com.ishop.model.wechat.WeChatOauthToken;
import com.ishop.model.wechat.WechatBindingPhoneRequest;
import com.walker.cache.CacheProvider;
import com.walker.infrastructure.utils.JsonUtils;
import com.walker.infrastructure.utils.MD5;
import com.walker.infrastructure.utils.NumberGenerator;
import com.walker.infrastructure.utils.PhoneNumberUtils;
import com.walker.infrastructure.utils.StringUtils;
import com.walker.web.CaptchaResult;
import com.walker.web.ResponseValue;
import com.walker.web.log.BusinessType;
import com.walker.web.log.OperateUser;
import com.walker.web.util.IdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.HashMap;
import java.util.Map;
 
@RestController
@RequestMapping("/front/login")
public class LoginApi extends BaseApi {
 
    private BlockPuzzleCaptchaProvider blockPuzzleCaptchaProvider;
    private CacheProvider<String> captchaCacheProvider;
    private SecuritySpi securitySpi;
    private WechatEngine wechatEngine;
 
    @Autowired
    public LoginApi(BlockPuzzleCaptchaProvider blockPuzzleCaptchaProvider
            , CacheProvider<String> captchaCacheProvider, SecuritySpi securitySpi, WechatEngine wechatEngine){
        this.blockPuzzleCaptchaProvider = blockPuzzleCaptchaProvider;
        this.captchaCacheProvider = captchaCacheProvider;
        this.securitySpi = securitySpi;
        this.wechatEngine = wechatEngine;
    }
 
    @RequestMapping(value = "/config", method = RequestMethod.GET)
    public ResponseValue getLoginConfig(){
        LoginConfigVo loginConfigVo = new LoginConfigVo();
        loginConfigVo.setLogo(this.getCdnUrl() + this.getArgumentVariable(ArgumentsConstants.CONFIG_KEY_MOBILE_LOGIN_LOGO).getStringValue());
        return ResponseValue.success(loginConfigVo);
    }
 
    /**
     * 微信注册绑定手机号
     * @return
     * @date 2023-08-07
     */
    @RequestMapping(value = "/wechat/register/binding/phone", method = RequestMethod.POST)
    public ResponseValue wechatRegisterBindingPhone(@RequestBody WechatBindingPhoneRequest request){
        if(request == null){
            return ResponseValue.error(Constants.ERROR_ARGUMENT);
        }
        logger.debug(request.toString());
 
        if(StringUtils.isEmpty(request.getKey())){
            return ResponseValue.error("微信参数为空:key");
        }
 
        String type = request.getType();
        if(StringUtils.isEmpty(type)){
            return ResponseValue.error("未找到请求类型:type");
        }
        if(type.equals(com.ishop.merchant.Constants.REGISTER_TYPE_WECHAT)
                || type.equals(com.ishop.merchant.Constants.REGISTER_TYPE_ROUTINE)
                || type.equals(com.ishop.merchant.Constants.REGISTER_TYPE_IOS_WX)
                || type.equals(com.ishop.merchant.Constants.REGISTER_TYPE_ANDROID_WX)){
            // 注册时
            if (type.equals(com.ishop.merchant.Constants.REGISTER_TYPE_WECHAT)
                    || type.equals(com.ishop.merchant.Constants.REGISTER_TYPE_IOS_WX)
                    || type.equals(com.ishop.merchant.Constants.REGISTER_TYPE_ANDROID_WX)) {
                if(StringUtils.isEmpty(request.getPhone())){
                    return ResponseValue.error("手机号不存在");
                }
                if(StringUtils.isEmpty(request.getCaptcha()) || StringUtils.isEmpty(request.getUuid())){
                    return ResponseValue.error("验证码不能为空");
                }
                if(!this.validateSmsCode(request.getCaptcha(), request.getUuid())){
                    return ResponseValue.error("验证码错误或已过期");
                }
            } else {
                // 小程序
                if (StringUtils.isEmpty(request.getCode())) {
                    return ResponseValue.error("小程序获取手机号code不能为空");
                }
                if (StringUtils.isEmpty(request.getEncryptedData())) {
                    return ResponseValue.error("请认证微信账号:获取手机号码失败");
                }
                if (StringUtils.isEmpty(request.getIv())) {
                    return ResponseValue.error("小程序获取手机号加密算法的初始向量不能为空");
                }
                String routineAppId = this.getArgumentVariable(WechatConstants.WECHAT_MINI_APPID).getStringValue();
                if(StringUtils.isEmpty(routineAppId)){
                    return ResponseValue.error("微信小程序appId未设置");
                }
 
                WechatMiniAuthorizeVo response = this.wechatEngine.getMiniAuthCode(request.getCode());
                logger.debug("请求微信登录小程序接口:{}", response);
 
                String decrypt = WechatUtils.decryptPhoneNumber(routineAppId, request.getEncryptedData(), response.getSessionKey(), request.getIv());
                if (StringUtils.isEmpty(decrypt)) {
                    return ResponseValue.error("微信小程序获取手机号解密失败");
                }
                try {
                    ObjectNode objectNode = JsonUtils.jsonStringToObjectNode(decrypt);
                    if(!objectNode.has("phoneNumber")){
                        logger.warn("没有解析到微信手机号,decrypt=" + decrypt);
                        return ResponseValue.error("没有解析到微信手机号,decrypt=" + decrypt);
                    }
                    String phone = objectNode.get("phoneNumber").textValue();
                    request.setPhone(phone);
                    logger.debug("解析到微信手机号:" + phone);
                } catch (Exception e) {
                    throw new RuntimeException("解密数据转json对象错误:" + decrypt, e);
                }
            }
 
            // 进入创建用户绑定手机号流程
            RegisterThirdUserRequest thirdUserRequest = this.getWechatOpenIdCache().get(request.getKey());
            if(thirdUserRequest == null){
                return ResponseValue.error("用户缓存已过期,请清除缓存重新登录");
            }
            if (!type.equals(thirdUserRequest.getType())) {
                return ResponseValue.error("用户的类型与缓存中的类型不符");
            }
 
            boolean isNew = true;
            String encryptPassword = null;
            // 查询是否用对应得token
            int userTokenType = LoginUtils.getUserTokenType(request.getType());
            S_user_core userCore = this.getUserService().queryLoginUserOnly(request.getPhone());
            if(userCore != null){
                // 历史用户校验
                if (type.equals(com.ishop.merchant.Constants.REGISTER_TYPE_WECHAT) && userCore.getIs_wechat_public().intValue() == 1) {
                    return ResponseValue.error("该手机号已绑定微信公众号");
                }
                if (type.equals(com.ishop.merchant.Constants.REGISTER_TYPE_ROUTINE) && userCore.getIs_wechat_routine().intValue() == 1) {
                    return ResponseValue.error("该手机号已绑定微信小程序");
                }
                if (type.equals(com.ishop.merchant.Constants.REGISTER_TYPE_ANDROID_WX) && userCore.getIs_wechat_android().intValue() == 1) {
                    return ResponseValue.error("该手机号已绑定微信Android");
                }
                if (type.equals(com.ishop.merchant.Constants.REGISTER_TYPE_IOS_WX) && userCore.getIs_wechat_ios().intValue() == 1) {
                    return ResponseValue.error("该手机号已绑定微信IOS");
                }
                EbUserToken userToken = this.getUserTokenService().queryToken(userCore.getId(), userTokenType);
                if (userToken != null) {
                    return ResponseValue.error("该手机号已被注册");
                }
 
                // 2023-09-15,微信公众号、小程序对应appid不同,因此openId也不同
                if(type.equals(com.ishop.merchant.Constants.REGISTER_TYPE_WECHAT)){
                    // 当是公众号时
                    userCore.setWx_open_id(thirdUserRequest.getOpenId());
                } else if (type.equals(com.ishop.merchant.Constants.REGISTER_TYPE_ROUTINE)) {
                    // 当是小程序时,暂时使用该union_id字段,因为不行更新平台用户表结构了。
                    userCore.setWx_union_id(thirdUserRequest.getOpenId());
                } else {
                    throw new UnsupportedOperationException("其他类型绑定手机号,暂未实现,type = " + type);
                }
 
                // 存在用户,但尚未绑定,更新绑定
                LoginUtils.setupBindType(userCore, type);
                this.getUserRegisterService().execUpdateBindUser(userCore, thirdUserRequest.getSpreadPid(), userTokenType, thirdUserRequest.getOpenId());
                this.getUserCacheProvider().updateUser(userCore);
                encryptPassword = userCore.getPassword();
                isNew = false;
                logger.debug("微信已有用户,绑定手机号成功");
            } else {
                // 新用户
                EbUser ebUser = this.registerUser(request.getPhone(), thirdUserRequest.getSpreadPid(), type, thirdUserRequest.getOpenId(), userTokenType);
                encryptPassword = ebUser.getPwd();
                logger.debug("微信新用户,绑定手机号成功");
            }
 
            // 执行登录过程
            try {
                RequestLogin requestLogin = LoginUtils.acquireRequestLoginByWechatPublic(request.getPhone(), encryptPassword);
                Map<String, Object> data = this.securitySpi.login(requestLogin);
                return ResponseValue.success(LoginUtils.acquireLoginInfoVo(data));
 
            } catch (LoginException ex) {
                logger.error("微信用户登录失败,openid = {}, key = {}", thirdUserRequest.getOpenId(), request.getKey());
                throw new PlatformRuntimeException("微信绑定,登录失败:" + ex.getMessage(), ex);
            }
 
        } else {
            // 登录时
            throw new UnsupportedOperationException("其他(微信)登录代码未实现,代码不会走到这里");
        }
    }
 
    /**
     * 微信登录小程序授权登录
     * @return
     * @date 2023-09-14
     */
    @RequestMapping(value = "/wechat/routine", method = RequestMethod.POST)
    public ResponseValue wechatRoutineLogin(@RequestBody RegisterThirdUserRequest request){
        if(request == null || StringUtils.isEmpty(request.getCode())){
            return ResponseValue.error("微信小程序授权参数为空");
        }
        logger.debug("调用了微信(小程序)授权登录接口:{}", request);
        WechatMiniAuthorizeVo response = this.wechatEngine.getMiniAuthCode(request.getCode());
 
        long spreadId = 0;
        if(request.getSpreadPid() != null){
            spreadId = request.getSpreadPid().longValue();
        }
 
        EbUserToken userToken = this.getUserTokenService().queryUserToken(request.getOpenId(), com.ishop.merchant.Constants.USER_TOKEN_TYPE_ROUTINE);
        if(userToken != null){
            logger.debug("已存在token关联用户,直接登录(微信小程序)");
            return this.doCreateWechatLoginData(userToken.getUid());
        }
 
        //
        LoginInfoVo vo = new LoginInfoVo();
 
        request.setSpreadPid(spreadId);
        request.setType(com.ishop.merchant.Constants.REGISTER_TYPE_ROUTINE);
        request.setOpenId(response.getOpenId());
 
        // 2023-08-13,这里记录调用参数和结果,方便调试为啥界面不能调准到手机绑定页面。
        this.systemLogSuccess(null, OperateUser.Mobile, BusinessType.Insert, "微信小程序获取:getMiniAuthCode", response.toString(), response.getOpenId());
 
        // 缓存openId相关内容
        String key = MD5.getMessageDigest(response.getOpenId().getBytes());
        this.getWechatOpenIdCache().save(key, request);
 
        vo.setType(com.ishop.merchant.Constants.LOGIN_STATUS_REGISTER);
        vo.setKey(key);
        return ResponseValue.success(vo);
    }
 
    /**
     * 微信公众号授权登录。
     * @return
     * @date 2023-07-25
     */
    @RequestMapping(value = "/wechat/public", method = RequestMethod.POST)
    public ResponseValue wechatPublicLogin(@RequestBody WechatLoginRequest request){
        if(request == null || StringUtils.isEmpty(request.getCode())){
            return ResponseValue.error("请求微信登录参数为空");
        }
        logger.debug("调用了微信授权登录接口:{}", request);
 
        long spreadId = 0;
        if(request.getSpreadPid() != null){
            spreadId = request.getSpreadPid().longValue();
        }
 
        // 通过code获取获取公众号授权信息
        WeChatOauthToken oauthToken = this.wechatEngine.getOauth2AccessToken(request.getCode());
        EbUserToken userToken = this.getUserTokenService().queryUserToken(oauthToken.getOpenid(), com.ishop.merchant.Constants.USER_TOKEN_TYPE_WECHAT);
 
        if(userToken != null){
            logger.debug("已存在token关联用户,直接登录(公众号)");
            return this.doCreateWechatLoginData(userToken.getUid());
        }
 
        LoginInfoVo vo = new LoginInfoVo();
 
        // 没有用户,走创建用户流程
        // 从微信获取用户信息,存入Redis中,将key返回给前端,前端在下一步绑定手机号的时候下发
        WeChatAuthorizeLoginUserInfoVo userInfo = this.wechatEngine.getSnsUserInfo(oauthToken.getAccess_token(), oauthToken.getOpenid());
        RegisterThirdUserRequest thirdUserRequest = new RegisterThirdUserRequest();
        thirdUserRequest.setOpenId(userInfo.getOpenid());
        thirdUserRequest.setType(com.ishop.merchant.Constants.REGISTER_TYPE_WECHAT);
        thirdUserRequest.setSpreadPid(spreadId);
        thirdUserRequest.setCode(request.getCode());
 
        // 2023-08-13,这里记录调用参数和结果,方便调试为啥界面不能调准到手机绑定页面。
        this.systemLogSuccess(null, OperateUser.Mobile, BusinessType.Insert, "微信获取:snsUserInfo", oauthToken.toString(), userInfo.toString());
 
        // 缓存openId相关内容
        String key = MD5.getMessageDigest(oauthToken.getOpenid().getBytes());
        this.getWechatOpenIdCache().save(key, thirdUserRequest);
 
        vo.setType(com.ishop.merchant.Constants.LOGIN_STATUS_REGISTER);
        vo.setKey(key);
        return ResponseValue.success(vo);
    }
 
    private ResponseValue doCreateWechatLoginData(long userId){
        S_user_core userCore = this.getUser(userId);
        RequestLogin requestLogin = LoginUtils.acquireRequestLoginByWechatPublic(userCore.getUser_name(), userCore.getPassword());
        try {
            Map<String, Object> data = this.securitySpi.login(requestLogin);
            return ResponseValue.success(LoginUtils.acquireLoginInfoVo(data));
        } catch (LoginException e) {
            return ResponseValue.error(e.getMessage());
        }
    }
 
    /**
     * 暂时使用,后续要删除该方法,需要调整前端。
     * @return
     * @date 2023-07-04
     */
//    @ApiOperation(value = "校验token是否有效")
    @RequestMapping(value = "/token/is/exist", method = RequestMethod.POST)
    public ResponseValue tokenIsExist(){
        if(this.getCurrentUser() == null){
            return ResponseValue.success(false);
        } else {
            return ResponseValue.success(true);
        }
    }
 
    /**
     * 手机号密码登录
     * @return
     * @date 2023-06-30
     */
    @RequestMapping(value = "/mobile/password", method = RequestMethod.POST)
    public ResponseValue phonePasswordLogin(@RequestBody LoginParam loginParam){
        if(loginParam == null
//                || StringUtils.isEmpty(loginParam.getUuid())
                || StringUtils.isEmpty(loginParam.getPassword())
                || StringUtils.isEmpty(loginParam.getPhone())){
            return ResponseValue.error("请输入登录信息");
        }
        if(!PhoneNumberUtils.isCellPhoneNumber(loginParam.getPhone())){
            return ResponseValue.error("手机号格式错误");
        }
        logger.debug(loginParam.toString());
 
        RequestLogin requestLogin = LoginUtils.acquireRequestLoginByPassword(loginParam);
        try {
            Map<String, Object> data = this.securitySpi.login(requestLogin);
            return ResponseValue.success(LoginUtils.acquireLoginInfoVo(data));
 
        } catch (LoginException e) {
            return ResponseValue.error(e.getMessage());
        }
    }
 
    /**
     * 手机号验证码登录,如果手机号不存在直接注册用户
     * @param loginParam
     * @return
     * @date 2023-06-30
     */
    @RequestMapping(value = "/mobile/captcha", method = RequestMethod.POST)
    public ResponseValue phoneCaptchaLogin(@RequestBody LoginParam loginParam){
        if(loginParam == null
                || StringUtils.isEmpty(loginParam.getUuid())
                || StringUtils.isEmpty(loginParam.getCaptcha())
                || StringUtils.isEmpty(loginParam.getPhone())){
            return ResponseValue.error("请输入登录信息");
        }
        if(!PhoneNumberUtils.isCellPhoneNumber(loginParam.getPhone())){
            return ResponseValue.error("手机号格式错误");
        }
        logger.debug(loginParam.toString());
 
        RequestLogin requestLogin = LoginUtils.acquireRequestLoginByCaptcha(loginParam);
        try {
            Map<String, Object> data = this.securitySpi.login(requestLogin);
            return ResponseValue.success(LoginUtils.acquireLoginInfoVo(data));
 
        } catch (LoginException e) {
//            logger.error("" + e.getMessage(), e);
            if(!e.isUserPhoneNotExist()){
                return ResponseValue.error(e.getMessage());
            }
 
            // 用户手机号不存在
            if(this.securitySpi.isAllowMobileLoginRegister()){
                // 检查平台是否关闭注册
                if(!this.getArgumentVariable(ArgumentsConstants.KEY_SECURITY_ACCOUNT_REGISTER).getBooleanValue()){
                    return ResponseValue.error(com.ishop.mobile.Constants.MSG_PLATFORM_REG_CLOSE);
                }
 
                logger.debug("用户手机号不存在,可以直接注册:" + requestLogin.getUsername());
                EbUser user = this.registerUser(requestLogin.getUsername(), loginParam.getSpreadPid(), null, null, 0);
                try {
                    Map<String, Object> data = this.securitySpi.login(requestLogin);
                    return ResponseValue.success(LoginUtils.acquireLoginInfoVo(data));
 
                } catch (LoginException ex) {
                    throw new RuntimeException(ex);
                }
//                return ResponseValue.error("手机号不存在,开发注册功能");
            }
            return ResponseValue.error("手机号不存在");
        }
    }
 
    /**
     * 注册一个系统移动端用户
     * @param phone
     * @param spreadUid
     * @param bindType 注册类型:
     * @param bindUserTokenType 和 bindType 一样,转换成数字了
     * @param bindToken 第三方,如:openId 等参数
     * @return
     */
    private EbUser registerUser(String phone, Long spreadUid, String bindType, String bindToken, int bindUserTokenType){
//        S_user_core userCore = new S_user_core();
//        userCore.setUser_name(phone);
//        userCore.setPhonenumber(phone);
//        userCore.setNick_name(com.ishop.mobile.Constants.REG_USER_PREFIX + StringUtils.generateRandomNumber(6));
//        userCore.setOrg_id(0L);
//        userCore.setDept_id(0L);
//        userCore.setUser_type(UserType.TYPE_APP_REG);
//        userCore.setPassword(this.getArgumentVariable(ArgumentsConstants.KEY_SECURITY_PASSWORD_INIT).getStringValue());
//        userCore.setSex("0");
//        userCore.setType(0);    // 普通用户,类型默认为0
//        userCore.setRegister_type(com.ishop.mobile.Constants.REGISTER_TYPE_H5);
//        userCore.setBind_mobile(1); // 这里(手机号不存在直接注册)肯定已绑定手机
//        userCore.setCreate_by("register");
//        userCore.setCreate_time(DateUtils.getDateTimeNumber());
//        userCore.setUpdate_time(userCore.getCreate_time());
        String defaultAvatar = this.getArgumentVariable(com.ishop.mobile.Constants.USER_DEFAULT_AVATAR_CONFIG_KEY).getStringValue();
        if(StringUtils.isNotEmpty(defaultAvatar)){
            defaultAvatar  = this.getCdnUrl() + defaultAvatar;
        }
        String defaultPassEncrypt = this.getArgumentVariable(ArgumentsConstants.KEY_SECURITY_PASSWORD_INIT).getStringValue();
        S_user_core userCore = LoginUtils.acquireMobileRegisterUserCore(phone, defaultPassEncrypt, defaultAvatar);
 
        userCore.setId(NumberGenerator.getLongSequenceNumber());    // 设置新创建用户平台ID,2023-09-03
        userCore.setWx_open_id(bindToken);  // 更新用户字段:wx_open_id,2023-08-23
        LoginUtils.setupBindType(userCore, bindType);
//        EbUser ebUser = new EbUser();
//        ebUser.setAccount(phone);
//        ebUser.setPwd(userCore.getPassword());
//        ebUser.setPhone(phone);
//        ebUser.setNickname(userCore.getNick_name());
//        ebUser.setSex(0);
//        ebUser.setRegisterType(userCore.getRegister_type());
//        ebUser.setAddress(StringUtils.EMPTY_STRING);
//        ebUser.setAvatar(this.getArgumentVariable(com.ishop.mobile.Constants.USER_DEFAULT_AVATAR_CONFIG_KEY).getStringValue());
//        ebUser.setLastLoginTime(userCore.getCreate_time());
//        ebUser.setCreateTime(userCore.getCreate_time());
        EbUser ebUser = LoginUtils.acquireMobileRegisterEbUser(phone, userCore, defaultAvatar);
 
        if(spreadUid != null){
            ebUser.setSpreadUid(spreadUid);
            ebUser.setSpreadTime(userCore.getCreate_time());
            logger.warn("需要后续添加处理分销的绑定关系,暂未实现!");
            // 绑定推广关系
//            bindSpread(user, spreadPid);
        } else {
            ebUser.setSpreadUid(0L);
        }
 
        // 2023-08-07
        EbUserToken userToken = null;
        if(StringUtils.isNotEmpty(bindToken)){
            userToken = VoUtils.acquireEbUserToken(bindUserTokenType, userCore.getId(), bindToken);
        }
 
        // 保存到数据库
        this.getUserRegisterService().execInsertMobileUserRegister(userCore, ebUser, null, userToken);
        // 保存缓存
        this.getUserCacheProvider().putUser(userCore);
        this.getUserRegCache().save(ebUser);
        return ebUser;
    }
 
    @RequestMapping(value = "/send/code")
    public ResponseValue sendSmsCode(@RequestBody SmsCodeParam param){
        if(param == null || StringUtils.isEmpty(param.getPhone())){
            return ResponseValue.error("请输入手机号");
        }
        logger.debug(param.toString());
        if(StringUtils.isEmpty(param.getUuid()) || StringUtils.isEmpty(param.getX())){
            return ResponseValue.error(Constants.ERROR_ARGUMENT);
        }
 
        // 验证拼图滑动结果
//        String verifyKey = Constants.CAPTCHA_CODE_PREFIX + param.getUuid();
//        String xSource = this.captchaCacheProvider.getCacheData(verifyKey);
        CaptchaResult captchaResult = new CaptchaResult();
        captchaResult.setUuid(param.getUuid());
        captchaResult.setCode(param.getX());
        boolean success = this.blockPuzzleCaptchaProvider.validateCaptcha(captchaResult);
        logger.debug("发送短信验证结果 = " + success);
        if(!success){
            return ResponseValue.error("验证失败,无法发送短信");
        }
 
        try{
            Map<String, Object> data = this.sendSmsCodeValidation(param.getPhone());
            return ResponseValue.success(data);
        } catch (Exception ex){
            logger.error("发送短信验证码错误:" + ex.getMessage(), ex);
            return ResponseValue.error(ex.getMessage());
        }
    }
 
    @RequestMapping("/captcha/jigsaw/mobile_validate")
    public ResponseValue validateJigsawMobileCaptcha(@RequestBody CaptchaParam param){
        if(param == null || StringUtils.isEmpty(param.getToken()) || StringUtils.isEmpty(param.getX())){
            return ResponseValue.error("未接收到验证输入信息!");
        }
        logger.debug(param.toString());
        CaptchaResult captchaResult = new CaptchaResult();
        captchaResult.setUuid(param.getToken());
        captchaResult.setCode(param.getX());
        Map<String, String> data = new HashMap<>(4);
        boolean success = this.blockPuzzleCaptchaProvider.validateCaptcha(captchaResult);
        if(!success){
            // 验证失败
            data.put("verify", "-1");
            return ResponseValue.success(data);
        }
 
        data.put("verify", "1");
        data.put("x", param.getX());
        data.put("uuid", param.getToken());    // uuid也要返回界面
        return ResponseValue.success(data);
    }
 
    @RequestMapping("/captcha/jigsaw/mobile")
    public ResponseValue generateJigsawMobileCaptcha(CaptchaParam param){
        String uuid = IdUtils.simpleUUID();
        Map<String, Object> data = new HashMap<>(4);
        data.put("uuid", uuid);
        String verifyKey = Constants.CAPTCHA_CODE_PREFIX + uuid;
        JigsawResult captchaResult = (JigsawResult)this.blockPuzzleCaptchaProvider.generateCaptcha(null);
        if(captchaResult == null || captchaResult.getX() == 0){
            return ResponseValue.error("拼图验证码生成错误, null");
        }
        // 写入验证码 x位置 到缓存中
        this.captchaCacheProvider.putCacheData(verifyKey, String.valueOf(captchaResult.getX()), 60);
        logger.debug("写入拼图验证位置,x = {}", captchaResult.getX());
 
        data.put("y", captchaResult.getY());
        data.put("slider", captchaResult.getImageBlockBase64());
        data.put("bg", captchaResult.getImageSourceBase64());
//        data.put("captchaEnabled", true);
        return ResponseValue.success(data);
    }
}