@源码地址来源: https://minglisoft.cn/honghu2/business.html
微信小程序登录代码:
/** * Copyright © 2012-2017 <a href="http://minglisoft.cn">HongHu</a> All rights reserved. */ package com.honghu.cloud.controller; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.security.AlgorithmParameters; import java.security.Security; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils; import org.bouncycastle.util.encoders.Base64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; 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.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.auth0.jwt.internal.org.bouncycastle.jce.provider.BouncyCastleProvider; import com.google.common.collect.Maps; import com.honghu.cloud.bean.User; import com.honghu.cloud.code.ResponseCode; import com.honghu.cloud.constant.Globals; import com.honghu.cloud.dto.AccessoryDto; import com.honghu.cloud.dto.PaymentDto; import com.honghu.cloud.dto.StoreDto; import com.honghu.cloud.dto.SysConfigDto; import com.honghu.cloud.dto.UserDto; import com.honghu.cloud.feign.AccessoryFeignClient; import com.honghu.cloud.feign.DistributionUserFeignClient; import com.honghu.cloud.feign.FtpFileFeignClient; import com.honghu.cloud.feign.PaymentFeignClient; import com.honghu.cloud.feign.StoreFeignClient; import com.honghu.cloud.feign.SysConfigFeignClient; import com.honghu.cloud.feign.TencentIMFeignClient; import com.honghu.cloud.redis.RedisUtil; import com.honghu.cloud.service.IUserService; import com.honghu.cloud.tools.SecurityUserHolder; import com.honghu.cloud.tools.wx.WXCore; import com.honghu.cloud.utils.CommUtil; import com.honghu.cloud.utils.Exceptions; import com.honghu.cloud.utils.HttpClientUtils; import com.honghu.cloud.utils.JWT; import com.honghu.cloud.utils.tools.Md5Encrypt; import lombok.extern.slf4j.Slf4j; import net.sf.json.JSONObject; /** * 微信小程序登录Controller * @author Administrator * */ @Slf4j @RestController @RequestMapping(value = "/weChat") public class WeChatLoginController { @Autowired private IUserService userService; @Autowired private RedisUtil redisUtil; @Autowired private SysConfigFeignClient sysConfigFeignClient; @Autowired private DistributionUserFeignClient disUserFeignClient; @Autowired private FtpFileFeignClient ftpFileFeignClient; @Autowired private TencentIMFeignClient tencentIMFeignClient; @Autowired private StoreFeignClient storeFeignClient; @Autowired private PaymentFeignClient paymentFeignClient; /* @Autowired private AccessoryFeignClient accessoryFeignClient;*/ private static final Logger logger = LoggerFactory.getLogger(WeChatLoginController.class); /***微信获取登录凭证url***/ private static final String CODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session"; /** * 小程序登录 * @param js_code 登录code * @param iv 加密算法的初始向量 * @param encryptedData 敏感用户数据 * @param share_uid 邀请注册用户 * @return */ @RequestMapping(value = "/login", method = RequestMethod.POST) public Map<String, Object> login(@RequestBody JSONObject json) { String js_code = json.optString("js_code"); String iv = json.optString("iv"); String encryptedData = json.optString("encryptedData"); String share_uid = json.optString("share_uid"); String source_type = json.optString("source_type"); String nickName = json.optString("nickName"); String userphoto = json.optString("photo"); /*SysConfigDto sysConfigDto = sysConfigFeignClient.getSysConfig(); String appid = sysConfigDto.getOpen_weixin_appId(); String secret = sysConfigDto.getOpen_weixin_appSecret();*/ // 微信APPID、微信密匙 Map<String, Object> param = Maps.newHashMap(); param.put("mark", "wx_miniprogram"); List<PaymentDto> payments = paymentFeignClient.queryPageList(param); PaymentDto payment =null; if (payments.size() > 0) { payment = (PaymentDto) payments.get(0); } if (payment==null||StringUtils.isEmpty(payment.getWx_appid()) || StringUtils.isEmpty(payment.getWx_appSecret())) { return ResponseCode.buildCodeMap("40031", "获取微信配置信息有误!", null); } Map<String,String> params = new HashMap<String, String>(); params.put("appid", payment.getWx_appid()); params.put("secret", payment.getWx_appSecret()); params.put("js_code", js_code); params.put("grant_type", "authorization_code"); String jsonStr = HttpClientUtils.doGet(CODE2SESSION_URL, params, "UTF-8"); JSONObject jsonObj = JSONObject.fromObject(jsonStr); // 错误码 String errcode = jsonObj.optString("errcode"); if(StringUtils.equals(errcode, "40028")){ // code 无效 return ResponseCode.buildCodeMap("40028", "code 无效!", null); } // errcode[-1:系统繁忙,此时请开发者稍候再试;45011:频率限制,每个用户每分钟100次] if(StringUtils.equals(errcode, "45011") || StringUtils.equals(errcode, "-1")){ return ResponseCode.buildCodeMap("45011", "系统繁忙,请稍后再试!", null); } String session_key = jsonObj.optString("session_key"); String openid = jsonObj.optString("openid"); // 会话密钥和用户唯一标识为空,表示服务请求失败,记录日志 if(StringUtils.isEmpty(session_key) || StringUtils.isEmpty(openid)){ return ResponseCode.buildCodeMap("40029", "code无效!", null); } // 解析小程序加密用户数据 String userInfo = WXCore.decrypt(payment.getWx_appid(), encryptedData, session_key, iv); if(StringUtils.isEmpty(userInfo)){ return ResponseCode.buildCodeMap("40030", "获取用户数据失败!", null); } JSONObject userJson = JSONObject.fromObject(userInfo); // 开放平台的唯一标识符 String unionid = userJson.optString("unionId"); if(StringUtils.isEmpty(unionid)){ return ResponseCode.buildCodeMap("40032", "获取用户数据失败!", null); } boolean phone=false; User user=null; boolean flag = false; //true 则不需要授权手机号 // 根据开放平台的唯一标识签,查询用户对象是否存在,不存在注册一条数据 synchronized (this) { user = userService.selectByUnionid(unionid); if(user != null && user.getSecurity() == 1){ return ResponseCode.buildCodeMap("40031", "账户存在安全隐患禁止登录!", null); } if (user!=null&&user.getUsername()!=null&&StringUtils.isNotBlank(user.getMobile())) { phone=true; } if(user == null){ flag = true; user = new User(); user.setOpenId(openid); if (StringUtils.isNotEmpty(nickName)) { user.setNickName(nickName); }else{ user.setNickName(userJson.optString("nickName")); //微信提供的默认头像 } user.setWeixin_unionID(unionid); user.setDay_msg_count(0); user.setDeleteStatus(0); user.setAddTime(new Date()); user.setPassword(Md5Encrypt.md5("123456").toLowerCase());//设置默认密码为123456 user.setYears(0); // 用户年龄 user.setIs_live(0); user.setLive_code(userService.selectMaxLiveCode() + 1); user.setUser_type(0); // 用户类别,默认为0个人用户,1为企业用户 user.setStore_apply_step(0); // 店铺申请进行的步骤,默认为0 user.setInvoiceType(0); // 发票类型 user.setWhether_attention(1); //是否允许关注 0为不允许,1为允许 user.setUser_form("miniProgram"); //注册来源,分为pc,android,ios,miniProgram, WXOffiaccount if (StringUtils.isNotEmpty(source_type)) { user.setSource_type(CommUtil.null2Int(source_type)); //1为海报 } userService.saveEntity(user); user = userService.selectByUnionid(unionid); }else if(StringUtils.equals(user.getUser_form(), "WXOffiaccount") && StringUtils.isBlank(user.getOpenId())){ //通过微信公众号注册的 user.setOpenId(openid); userService.updateById(user); flag = true; //微信注册第一次进来分销关系重新建立 } } boolean isUpdate=false; // 处理用户头像(用户头像不存在,将微信的头像保存到用户头像) //String photo_url = userJson.optString("avatarUrl"); if(user.getPhoto_id() == null && StringUtils.isNotEmpty(userphoto)){ AccessoryDto photo = uploadPhotoFile(userphoto, user.getId()); if(photo != null){ user.setPhoto(photo); user.setPhoto_id(photo.getId()); isUpdate=true; } } //用户换名称或头像 if(user.getNickName()==null){ user.setNickName(nickName); isUpdate=true; } if (user.getLive_code()==null) { user.setLive_code(userService.selectMaxLiveCode() + 1); isUpdate=true; } if (StringUtils.isNotEmpty(nickName) && StringUtils.isEmpty(user.getNickName())) { user.setNickName(nickName); isUpdate = true; } if (StringUtils.isEmpty(user.getOpenId())) { user.setOpenId(openid); isUpdate = true; } if (isUpdate) { userService.updateById(user); } //所有用户都是分销用户 if(flag){ userService.saveDisUser(user, share_uid); } // 生成token,格式:用户id;时间戳 String token = JWT.sign(user.getId() + ";" + System.currentTimeMillis()+";"+"small", 0); // 将token存到redis中,有效期24小时 redisUtil.set(Globals.WECHAT_LOGIN_MARK + user.getId(), token, Globals.USER_INFO_EXPIRE_TIME); // 覆盖redis用户信息 UserDto userDto = new UserDto(); BeanUtils.copyProperties(user, userDto); redisUtil.set(Globals.USER_INFO_MARK + user.getId(), userDto, Globals.USER_INFO_EXPIRE_TIME); String storestatus=""; if (userDto.getStore_id()!=null) { StoreDto storeDto = storeFeignClient.selectByPrimaryKey(userDto.getStore_id()); if (storeDto!=null) { storestatus=storeDto.getStore_status()+""; } } HashMap<String, Object> result = new HashMap<>(); result.put("token", token); result.put("storestatus", storestatus); SysConfigDto sysConfig = sysConfigFeignClient.getSysConfig(); if (sysConfig.getOpen_live()==0) { result.put("phone", true); }else{ result.put("phone", phone); } result.put("session_key", session_key); result.put("user", user); if (user != null&&user.getIs_live()!=null) { result.put("is_live", user.getIs_live()==2?true:false); }else{ result.put("is_live", false); } return ResponseCode.buildSuccessMap(result); } /** * 保存用户手机号 * @return */ @RequestMapping(value = "/savePhone", method = RequestMethod.POST) public Map<String, Object> savePhone(HttpServletRequest request, @RequestBody JSONObject json) { String session_key = json.optString("session_key"); String iv = json.optString("iv"); String encryptedData = json.optString("encrypData"); if (StringUtils.isBlank(session_key)) { return ResponseCode.buildFailMap("获取失败,session_key信息错误", null); } if (StringUtils.isBlank(iv)) { return ResponseCode.buildFailMap("获取失败,iv信息错误", null); } if (StringUtils.isBlank(encryptedData)) { return ResponseCode.buildFailMap("获取失败,encryptedData信息错误", null); } byte[] dataByte = Base64.decode(encryptedData); // 加密秘钥 byte[] keyByte = Base64.decode(session_key); // 偏移量 byte[] ivByte = Base64.decode(iv); try { // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要 int base = 16; if (keyByte.length % base != 0) { int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0); byte[] temp = new byte[groups * base]; Arrays.fill(temp, (byte) 0); System.arraycopy(keyByte, 0, temp, 0, keyByte.length); keyByte = temp; } // 初始化 Security.addProvider(new BouncyCastleProvider()); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpec spec = new SecretKeySpec(keyByte, "AES"); AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES"); parameters.init(new IvParameterSpec(ivByte)); cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化 byte[] resultByte = cipher.doFinal(dataByte); if (null != resultByte && resultByte.length > 0) { String result = new String(resultByte, "UTF-8"); JSONObject fromObject = JSONObject.fromObject(result); Object object = fromObject.get("purePhoneNumber"); User user = userService.selectByPrimaryKey(SecurityUserHolder.getCurrentUserId(request)); //查询是否已经存在该手机号 User UserName = userService.selectByUserName(CommUtil.null2String(object)); //需要合并用户 , 手机号存在, 并且 unionid 为空 if (UserName!=null&&StringUtils.isEmpty(UserName.getWeixin_unionID())) { UserName.setWeixin_unionID(user.getWeixin_unionID()); //将新unionid 存入旧数据中 if (UserName.getLive_code()==null) { UserName.setLive_code(userService.selectMaxLiveCode() + 1); } if (StringUtils.isEmpty(UserName.getNickName())) { UserName.setNickName(user.getNickName()); } if (user.getPhoto_id()!=null) { UserName.setPhoto_id(user.getPhoto_id()); } if (user.getOpenId()!=null) { UserName.setOpenId(user.getOpenId()); } if (user.getWx_open_id()!=null) { UserName.setWx_open_id(user.getWx_open_id());; } userService.updateById(UserName); user.setDeleteStatus(1); user.setMobile("del"+CommUtil.null2String(object)); user.setUserName("del"+CommUtil.null2String(object)); user.setWeixin_unionID("del"+UserName.getId()+""); userService.updateById(user); disUserFeignClient.deleteByUserId(user.getId()); //删除新的 分销关系表 redisUtil.remove(Globals.WECHAT_LOGIN_MARK + user.getId()); //换用户登录 // 生成token,格式:用户id;时间戳 String token = JWT.sign(UserName.getId() + ";" + System.currentTimeMillis()+";"+"small", 0); // 将token存到redis中,有效期24小时 redisUtil.set(Globals.WECHAT_LOGIN_MARK + UserName.getId(), token, Globals.USER_INFO_EXPIRE_TIME); // 覆盖redis用户信息 UserDto userDto = new UserDto(); BeanUtils.copyProperties(UserName, userDto); redisUtil.set(Globals.USER_INFO_MARK + UserName.getId(), userDto, Globals.USER_INFO_EXPIRE_TIME); return ResponseCode.buildSuccessMap(token); } //删除 /*//手机号跟原来一致, 直接通过 if (CommUtil.null2String(object).equals(user.getUserName())) { return ResponseCode.buildSuccessMap("isOk"); }*/ //手机号已存在 if (UserName!=null) { return ResponseCode.buildFailMap("手机号已存在", "false"); } user.setUserName(CommUtil.null2String(object)); user.setMobile(CommUtil.null2String(object)); userService.updateById(user); return ResponseCode.buildSuccessMap(null); } } catch (Exception e) { e.printStackTrace(); } return ResponseCode.buildFailMap("信息有误", "false"); } /** * 分享邀请用户注册的分享链接 * @return */ @RequestMapping(value = "/shareLogin", method = RequestMethod.POST) public Map<String, Object> shareLogin( HttpServletRequest request) { UserDto user = SecurityUserHolder.getCurrentUser(request); if(user == null || user.getId() == null){ return ResponseCode.buildEnumMap(ResponseCode.TOKEN_EXPIRE, null); } return ResponseCode.buildSuccessMap(user.getId()); } /** * 分享邀请用户注册的分享链接 * @return */ @RequestMapping(value = "/checkUserPhone", method = RequestMethod.POST) public Map<String, Object> checkUserPhone( HttpServletRequest request) { UserDto user = SecurityUserHolder.getCurrentUser(request); if(user == null || user.getId() == null){ return ResponseCode.buildEnumMap(ResponseCode.TOKEN_EXPIRE, null); } User new_user = userService.selectByPrimaryKey(user.getId()); if (new_user.getMobile()==null||new_user.getUserName()==null) { return ResponseCode.buildEnumMap(ResponseCode.RESPONSE_CODE_USER_MOBILE_OR_TELEPHONE_NOT_EMPTY, null); } return ResponseCode.buildSuccessMap(null); } /** * 分享邀请用户购买商品的分享链接 * @return */ @RequestMapping(value = "/shareGoods", method = RequestMethod.POST) public Map<String, Object> shareGoods( HttpServletRequest request) { UserDto user = SecurityUserHolder.getCurrentUser(request); if(user == null || user.getId() == null){ return ResponseCode.buildEnumMap(ResponseCode.TOKEN_EXPIRE, null); } return ResponseCode.buildSuccessMap(user.getId()); } /** * @Description 将字符串中的emoji表情转换成可以在utf-8字符集数据库中保存的格式(表情占4个字节,需要utf8mb4字符集) * @param str * 待转换字符串 * @return 转换后字符串 * @throws UnsupportedEncodingException * exception */ public static String emojiConvert1(String str) { String patternString = "([\\x{10000}-\\x{10ffff}\ud800-\udfff])"; Pattern pattern = Pattern.compile(patternString); Matcher matcher = pattern.matcher(str); StringBuffer sb = new StringBuffer(); while (matcher.find()) { try { matcher.appendReplacement(sb, "[[" + URLEncoder.encode(matcher.group(1), "UTF-8") + "]]"); } catch (Exception e) { } } matcher.appendTail(sb); return sb.toString(); } /** * 微信授权登录上传头像 * @param photo_url * @param user_id * @return */ public AccessoryDto uploadPhotoFile(String photo_url, Long user_id){ try { AccessoryDto accessoryDto = ftpFileFeignClient.upload("user/image", "", "JPG", user_id, photo_url); return accessoryDto; } catch (Exception e) { log.error("微信授权登录上传头像失败:"+Exceptions.getStackTraceAsString(e)); } return null; } /** * 将全部的用户注册IM账号 * @return */ @RequestMapping(value = "/IM/outImportMultipleAccounts", method = RequestMethod.GET) public boolean outImportMultipleAccounts() { //获取所有用户的信息 Map<String, Object> params = new HashMap<String, Object>(); params.put("deleteStatus", "0"); int count = userService.selectCount(params); int pageNum = (count/100)+1; //腾讯只支持最多100个账号删除 boolean bol = true; for(int i = 1; i <= pageNum; i++){ params.put("currentPage", i); params.put("pageSize", 100); List<User> list = userService.queryPages(params); List<String> uids = new ArrayList<String>(); for (User user : list) { uids.add(user.getId().toString()); } bol = tencentIMFeignClient.importMultipleAccounts(uids); } return bol; } /** * 将全部的用户注册IM账号 * @return */ @RequestMapping(value = "/IM/outAccountDelete", method = RequestMethod.GET) public boolean outAccountDelete() { //获取所有用户的信息 Map<String, Object> params = new HashMap<String, Object>(); params.put("deleteStatus", "0"); int count = userService.selectCount(params); int pageNum = (count/100)+1; //腾讯只支持最多100个账号删除 boolean bol = true; for(int i = 1; i <= pageNum; i++){ params.put("currentPage", i); params.put("pageSize", 100); List<User> list = userService.queryPages(params); List<String> uids = new ArrayList<String>(); for (User user : list) { uids.add(user.getId().toString()); } bol = tencentIMFeignClient.accountDelete(uids); } return bol; } /** * 微信授权登录 * @param code 授权临时票据 * @return map * @throws Exception */ @RequestMapping(value = "/weChatLogin" , method = RequestMethod.GET) public Map<String, Object> weChatLogin(@RequestParam("code") String code) throws Exception { return userService.weChatLogin(code); } /** * 微信授权登录(uniapp使用) * @param code 授权临时票据 * @return map * @throws Exception */ @RequestMapping(value = "/appWeChatLogin" , method = RequestMethod.POST) public Map<String, Object> appWeChatLogin(@RequestBody JSONObject json) throws Exception { return userService.appWeChatLogin(json); } @RequestMapping(value = "/appWeChatLoginNew" , method = RequestMethod.POST) public Map<String, Object> appWeChatLoginNew(@RequestBody JSONObject json) throws Exception { return userService.appWeChatLoginNew(json); } /** * 微信授权登录 * @param code 授权临时票据 * @return map * @throws Exception */ @RequestMapping(value = "/weChatH5Login" , method = RequestMethod.GET) public Map<String, Object> weChatH5Login(@RequestParam("code") String code) throws Exception { return userService.weChatH5Login(code); } }
@源码地址来源: https://minglisoft.cn/honghu2/business.html