소스 검색

业主小程序支持一键登陆

wuxw 1 년 전
부모
커밋
c2f8529b15

+ 1 - 0
service-api/src/main/java/com/java110/api/configuration/ServiceConfiguration.java

@@ -55,6 +55,7 @@ public class ServiceConfiguration {
         exclusions.append("/app/loginOwner,");// 业主APP登录跳过
         exclusions.append("/app/loginOwnerByKey,");// 根据key登录业主
         exclusions.append("/app/user.ownerUserLogin,");// 业主登录(新)
+        exclusions.append("/app/login.phoneWechatLogin,");// 微信一键登陆
         exclusions.append("/app/area.listAreas,");// 加载地区
         exclusions.append("/app/community.listCommunitys,");// 加载小区
         exclusions.append("/app/user.userSendSms,");// 发送短信验证码

+ 337 - 0
service-user/src/main/java/com/java110/user/cmd/login/PhoneWechatLoginCmd.java

@@ -0,0 +1,337 @@
+package com.java110.user.cmd.login;
+
+import com.alibaba.fastjson.JSONObject;
+import com.java110.core.annotation.Java110Cmd;
+import com.java110.core.client.RestTemplate;
+import com.java110.core.context.ICmdDataFlowContext;
+import com.java110.core.event.cmd.Cmd;
+import com.java110.core.event.cmd.CmdEvent;
+import com.java110.core.factory.AuthenticationFactory;
+import com.java110.core.factory.GenerateCodeFactory;
+import com.java110.core.log.LoggerFactory;
+import com.java110.dto.community.CommunityDto;
+import com.java110.dto.owner.OwnerAppUserDto;
+import com.java110.dto.owner.OwnerDto;
+import com.java110.dto.system.SystemInfoDto;
+import com.java110.dto.user.LoginOwnerResDto;
+import com.java110.dto.user.UserAttrDto;
+import com.java110.dto.user.UserDto;
+import com.java110.dto.wechat.SmallWeChatDto;
+import com.java110.intf.common.ISystemInfoV1InnerServiceSMO;
+import com.java110.intf.community.ICommunityInnerServiceSMO;
+import com.java110.intf.job.IIotInnerServiceSMO;
+import com.java110.intf.job.IMallInnerServiceSMO;
+import com.java110.intf.store.ISmallWechatV1InnerServiceSMO;
+import com.java110.intf.user.IOwnerAppUserV1InnerServiceSMO;
+import com.java110.intf.user.IOwnerV1InnerServiceSMO;
+import com.java110.intf.user.IUserAttrV1InnerServiceSMO;
+import com.java110.intf.user.IUserV1InnerServiceSMO;
+import com.java110.po.owner.OwnerAppUserPo;
+import com.java110.po.user.UserAttrPo;
+import com.java110.po.user.UserPo;
+import com.java110.utils.constant.CommonConstant;
+import com.java110.utils.exception.CmdException;
+import com.java110.utils.util.Assert;
+import com.java110.utils.util.BeanConvertUtil;
+import com.java110.utils.util.ListUtil;
+import com.java110.utils.util.StringUtil;
+import com.java110.vo.ResultVo;
+import org.apache.commons.net.util.Base64;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * 微信一键登陆
+ */
+@Java110Cmd(serviceCode = "login.phoneWechatLogin")
+public class PhoneWechatLoginCmd extends Cmd {
+    private final static Logger logger = LoggerFactory.getLogger(PhoneWechatLoginCmd.class);
+
+    @Autowired
+    private ISmallWechatV1InnerServiceSMO smallWechatV1InnerServiceSMOImpl;
+
+    @Autowired
+    private RestTemplate outRestTemplate;
+
+    @Autowired
+    private IUserV1InnerServiceSMO userV1InnerServiceSMOImpl;
+
+    @Autowired
+    private IOwnerAppUserV1InnerServiceSMO ownerAppUserV1InnerServiceSMOImpl;
+
+    @Autowired
+    private IUserAttrV1InnerServiceSMO userAttrV1InnerServiceSMOImpl;
+
+    @Autowired
+    private IOwnerV1InnerServiceSMO ownerV1InnerServiceSMOImpl;
+
+    @Autowired
+    private ICommunityInnerServiceSMO communityInnerServiceSMOImpl;
+
+    @Autowired
+    private IMallInnerServiceSMO mallInnerServiceSMOImpl;
+
+    @Autowired
+    private IIotInnerServiceSMO iotInnerServiceSMOImpl;
+
+    @Autowired
+    private ISystemInfoV1InnerServiceSMO systemInfoV1InnerServiceSMOImpl;
+
+
+    @Override
+    public void validate(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException {
+        Assert.hasKeyAndValue(reqJson, "encryptedData", "未包含encryptedData");
+        Assert.hasKeyAndValue(reqJson, "iv", "未包含iv");
+        Assert.hasKeyAndValue(reqJson, "code", "未包含code");
+        Assert.hasKeyAndValue(reqJson, "appId", "未包含appId");
+    }
+
+    @Override
+    public void doCmd(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException {
+
+
+        //调用微信获取手机号
+        String code = reqJson.getString("code");
+        String encryptedData = reqJson.getString("encryptedData");
+        String iv = reqJson.getString("iv");
+        String appId = reqJson.getString("appId");
+
+        SmallWeChatDto smallWeChatDto = new SmallWeChatDto();
+        smallWeChatDto.setAppId(appId);
+        List<SmallWeChatDto> smallWeChatDtos = smallWechatV1InnerServiceSMOImpl.querySmallWechats(smallWeChatDto);
+        if (ListUtil.isNull(smallWeChatDtos)) {
+            throw new CmdException("未配置小程序信息");
+        }
+
+        String sessionKey = getSessionKey(code, smallWeChatDtos.get(0));
+
+        if (sessionKey == null) {
+            throw new CmdException("获取session_key失败");
+        }
+
+        // 3. 解密手机号
+        String phoneNumber = "";
+        try {
+            phoneNumber = decryptData(encryptedData, iv, sessionKey);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new CmdException(e.getMessage());
+        }
+
+        if (StringUtil.isEmpty(phoneNumber)) {
+            throw new CmdException("获取手机号失败");
+        }
+
+        UserDto userDto = new UserDto();
+        userDto.setTel(phoneNumber);
+        userDto.setLevelCd(UserDto.LEVEL_CD_USER);
+        List<UserDto> userDtos = userV1InnerServiceSMOImpl.queryUsers(userDto);
+        if (ListUtil.isNull(userDtos)) {
+            registerUser(phoneNumber);
+            userDtos = userV1InnerServiceSMOImpl.queryUsers(userDto);
+        }
+        //todo 1.2 同步物业用户资料给商城
+        mallInnerServiceSMOImpl.sendUserInfo(userDtos.get(0));
+
+        //todo 1.3 同步物业用户资料给物联网
+        iotInnerServiceSMOImpl.sendUserInfo(userDtos.get(0));
+
+        String communityId = "";
+        //todo 查询业主是否 认证了,如果认证了获取小区ID
+        OwnerAppUserDto ownerAppUserDto = new OwnerAppUserDto();
+        ownerAppUserDto.setUserId(userDtos.get(0).getUserId());
+        ownerAppUserDto.setLink(userDtos.get(0).getTel());
+        ownerAppUserDto.setState(OwnerAppUserDto.STATE_AUDIT_SUCCESS);
+        List<OwnerAppUserDto> ownerAppUserDtos = ownerAppUserV1InnerServiceSMOImpl.queryOwnerAppUsers(ownerAppUserDto);
+
+        if (ListUtil.isNull(ownerAppUserDtos)) {
+            autoBindUserToOwner(userDtos.get(0), phoneNumber);
+            communityId = smallWeChatDtos.get(0).getObjId();
+        } else {
+            communityId = ownerAppUserDtos.get(0).getCommunityId();
+        }
+
+        CommunityDto communityDto = new CommunityDto();
+        communityDto.setCommunityId(communityId);
+        List<CommunityDto> communityDtos = communityInnerServiceSMOImpl.queryCommunitys(communityDto);
+        Assert.listOnlyOne(communityDtos, "小区不存在,确保开发者账户配置默认小区" + communityId);
+
+
+        //todo 生成 app 永久登录key
+        UserDto tmpUserDto = userDtos.get(0);
+        String newKey = generatorLoginKey(tmpUserDto);
+
+        //todo 生成登录token
+        String token = generatorLoginToken(tmpUserDto);
+        LoginOwnerResDto loginOwnerResDto = new LoginOwnerResDto();
+
+        loginOwnerResDto.setCommunityId(communityDtos.get(0).getCommunityId());
+        loginOwnerResDto.setCommunityName(communityDtos.get(0).getName());
+        loginOwnerResDto.setCommunityTel(communityDtos.get(0).getTel());
+        loginOwnerResDto.setCommunityQrCode(communityDtos.get(0).getQrCode());
+        loginOwnerResDto.setUserId(tmpUserDto.getUserId());
+        loginOwnerResDto.setUserName(tmpUserDto.getName());
+        loginOwnerResDto.setOwnerTel(tmpUserDto.getTel());
+        loginOwnerResDto.setToken(token);
+        loginOwnerResDto.setKey(newKey);
+        context.setResponseEntity(ResultVo.createResponseEntity(loginOwnerResDto));
+    }
+
+    private void autoBindUserToOwner(UserDto userDto, String phoneNumber) {
+        // todo 查询业主或成员
+        OwnerDto ownerDto = new OwnerDto();
+        ownerDto.setLink(phoneNumber);
+        ownerDto.setPage(1);
+        ownerDto.setRow(1);
+        List<OwnerDto> ownerDtos = ownerV1InnerServiceSMOImpl.queryOwners(ownerDto);
+
+        // 说明业主不存在 直接返回跑异常
+        if (ListUtil.isNull(ownerDtos)) {
+            return;
+        }
+        CommunityDto communityDto = new CommunityDto();
+        communityDto.setCommunityId(ownerDtos.get(0).getCommunityId());
+        List<CommunityDto> communityDtos = communityInnerServiceSMOImpl.queryCommunitys(communityDto);
+        if (ListUtil.isNull(communityDtos)) {
+            return;
+        }
+        CommunityDto tmpCommunityDto = communityDtos.get(0);
+
+        OwnerAppUserPo ownerAppUserPo = new OwnerAppUserPo();
+        //状态类型,10000 审核中,12000 审核成功,13000 审核失败
+        ownerAppUserPo.setState("12000");
+        ownerAppUserPo.setAppTypeCd("10010");
+        ownerAppUserPo.setAppUserId(GenerateCodeFactory.getGeneratorId(GenerateCodeFactory.CODE_PREFIX_appUserId));
+        ownerAppUserPo.setMemberId(ownerDtos.get(0).getMemberId());
+        ownerAppUserPo.setCommunityName(tmpCommunityDto.getName());
+        ownerAppUserPo.setCommunityId(ownerDtos.get(0).getCommunityId());
+        ownerAppUserPo.setAppUserName(ownerDtos.get(0).getName());
+        ownerAppUserPo.setIdCard(ownerDtos.get(0).getIdCard());
+        ownerAppUserPo.setAppType("WECHAT");
+        ownerAppUserPo.setLink(ownerDtos.get(0).getLink());
+        ownerAppUserPo.setUserId(userDto.getUserId());
+        ownerAppUserPo.setOpenId("-1");
+        ownerAppUserV1InnerServiceSMOImpl.saveOwnerAppUser(ownerAppUserPo);
+    }
+
+    private void registerUser(String phoneNumber) {
+        // 密码就随机数
+        String userPassword = AuthenticationFactory.passwdMd5(GenerateCodeFactory.getRandomCode(6));
+
+        UserPo userPo = new UserPo();
+        userPo.setUserId(GenerateCodeFactory.getGeneratorId("30"));
+        userPo.setName(phoneNumber);
+        userPo.setTel(phoneNumber);
+        userPo.setLevelCd(UserDto.LEVEL_CD_USER);
+        userPo.setPassword(AuthenticationFactory.passwdMd5(userPassword));
+        int flag = userV1InnerServiceSMOImpl.saveUser(userPo);
+        if (flag < 1) {
+            throw new CmdException("注册失败");
+        }
+    }
+
+    private String getSessionKey(String code, SmallWeChatDto smallWeChatDto) {
+
+
+        String secret = smallWeChatDto.getAppSecret();
+        String url = String.format(
+                "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
+                smallWeChatDto.getAppId(), secret, code
+        );
+        String responseStr = outRestTemplate.getForObject(url, String.class);
+        JSONObject response = JSONObject.parseObject(responseStr);
+
+        if (response == null || response.containsKey("errcode")) {
+            throw new CmdException("微信接口调用失败");
+        }
+
+        return response.getString("session_key");
+    }
+
+    public String decryptData(String encryptedData, String iv, String sessionKey) throws Exception {
+        byte[] keyBytes = Base64.decodeBase64(sessionKey);
+        byte[] ivBytes = Base64.decodeBase64(iv);
+        byte[] encryptedDataBytes = Base64.decodeBase64(encryptedData);
+
+        // 初始化AES cipher
+        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
+        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
+        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
+
+        // 解密数据
+        byte[] decryptedBytes = cipher.doFinal(encryptedDataBytes);
+        String decryptedText = new String(decryptedBytes, StandardCharsets.UTF_8);
+
+        JSONObject data = JSONObject.parseObject(decryptedText);
+
+        // 解析JSON获取手机号
+        // 实际项目中应该使用JSON解析库
+        // 这里简化为直接返回
+        return data.getString("purePhoneNumber");
+    }
+
+    private String generatorLoginKey(UserDto tmpUserDto) {
+        List<UserAttrDto> userAttrDtos = tmpUserDto.getUserAttrs();
+        UserAttrDto userAttrDto = getCurrentUserAttrDto(userAttrDtos, UserAttrDto.SPEC_KEY);
+        String newKey = UUID.randomUUID().toString();
+        if (userAttrDto != null) {
+            UserAttrPo userAttrPo = BeanConvertUtil.covertBean(userAttrDto, UserAttrPo.class);
+            userAttrPo.setValue(newKey);
+            userAttrPo.setStatusCd("0");
+            userAttrV1InnerServiceSMOImpl.updateUserAttr(userAttrPo);
+        } else {
+            UserAttrPo userAttrPo = new UserAttrPo();
+            userAttrPo.setAttrId(GenerateCodeFactory.getAttrId());
+            userAttrPo.setUserId(tmpUserDto.getUserId());
+            userAttrPo.setSpecCd(UserAttrDto.SPEC_KEY);
+            userAttrPo.setValue(newKey);
+            userAttrPo.setStatusCd("0");
+            userAttrV1InnerServiceSMOImpl.saveUserAttr(userAttrPo);
+        }
+        return newKey;
+    }
+
+    private UserAttrDto getCurrentUserAttrDto(List<UserAttrDto> userAttrDtos, String specCd) {
+        if (userAttrDtos == null) {
+            return null;
+        }
+        for (UserAttrDto userAttrDto : userAttrDtos) {
+            if (specCd.equals(userAttrDto.getSpecCd())) {
+                return userAttrDto;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * 生成登录key
+     *
+     * @param tmpUserDto
+     * @return
+     */
+    private static String generatorLoginToken(UserDto tmpUserDto) {
+        String token;
+        try {
+            Map userMap = new HashMap();
+            userMap.put(CommonConstant.LOGIN_USER_ID, tmpUserDto.getUserId());
+            userMap.put(CommonConstant.LOGIN_USER_NAME, tmpUserDto.getUserName());
+            token = AuthenticationFactory.createAndSaveToken(userMap);
+        } catch (Exception e) {
+            logger.error("登录异常:", e);
+            throw new CmdException("系统内部错误,请联系管理员");
+        }
+        return token;
+    }
+}

+ 1 - 1
service-user/src/main/java/com/java110/user/cmd/user/UserLoginCmd.java

@@ -192,7 +192,7 @@ public class UserLoginCmd extends Cmd {
         List<OwnerDto> ownerDtos = ownerV1InnerServiceSMOImpl.queryOwners(ownerDto);
 
         // 说明业主不存在 直接返回跑异常
-        if (ownerDtos == null || ownerDtos.size() < 1) {
+        if (ListUtil.isNull(ownerDtos)) {
             return null;
         }