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 captchaCacheProvider; private SecuritySpi securitySpi; private WechatEngine wechatEngine; @Autowired public LoginApi(BlockPuzzleCaptchaProvider blockPuzzleCaptchaProvider , CacheProvider 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 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 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 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 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 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 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 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 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); } }