资讯详情

java获取小程序中用户的unionId的三种方式

想要获取unionId,同一主体下必须有几个小程序或者微信官方账号,否则就没有了unionId,只生成用户openid,可登录以下微信官方平台查看

https://open.weixin.qq.com

注:用户未注意官方账号前端常规调用wx.login()得不到unionid,

解决方案(仅供参考,实际测量有效):在满足上述条件的情况下,前端先转移wx.login后得到SessionKey

前端再调用wx.getUserInfo接口(此时带登录态)

返回给后端wx.getUserInfo在接口中获取vi和encryptedData SessionKey即可获取unionId

使用weixin-java-miniapp实现微信小程序登录接口 个人认为代码最整洁

maven 依赖

<!--微信开源包装sdk--> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-miniapp</artifactId> <version>3.6.0</version> </dependency>

<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.10</version> <scope>provided</scope> </dependency>

PS:不想导入lombok请给LoginRequest的字段加上getter/setter方法 去掉@Data

@Data public class LoginRequest { ///用户登录凭证 String code;

///原始数据字符串 String signature;

/// String rawData;

//加密用户数据 String encryptedData;

////加密算法的初始向量 String iv; } 主要代码

import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl; import me.chanjar.weixin.common.error.WxErrorException;

/** * @describe: 类描述信息 * @author: zwr * @date: 2020/3/26/13:48 PM */ public class WxAppLoginService {

private WxMaService getWxMaService() {     WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();     config.setAppid( ResourceUtil.getConfigByName("wx.appId")); ///这是你自己的小程序appid,     config.setSecret(ResourceUtil.getConfigByName("wx.secret"));     config.setMsgDataFormat("JSON");     WxMaService wxMaService = new WxMaServiceImpl();     wxMaService.setWxMaConfig(config);     return wxMaService; }

public void login(LoginRequest request) throws WxErrorException { final WxMaService wxService = getWxMaService();

// 获取微信用户session WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(request.getCode()); if (null == session) { throw new RuntimeException("login handler error"); }

// 解密用户信息 WxMaUserInfo wxUserInfo = wxService.getUserService().getUserInfo(session.getSessionKey(), request.getEncryptedData(), request.getIv()); if (null == wxUserInfo) { throw new RuntimeException("获取失败"); } String unionId = wxUserInfo.getUnionId();

}

}

在maven中的pom引入为

<!--微信解密 --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-ext-jdk15on</artifactId> <version>1.55</version> </dependency> import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec;br> import javax.crypto.spec.SecretKeySpec;     import org.bouncycastle.jce.provider.BouncyCastleProvider;     import java.security.*;   public class AES {     /**      * AES解密      * @param content 密文      * @return      * @throws InvalidAlgorithmParameterException      * @throws NoSuchProviderException      */     public static final String ALGORITHM = "AES/CBC/PKCS7Padding";     public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {         try {            Security.addProvider(new BouncyCastleProvider());             Cipher cipher = Cipher.getInstance(ALGORITHM,"BC");             Key sKeySpec = new SecretKeySpec(keyByte, "AES");             cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化             byte[] result = cipher.doFinal(content);             return result;         } catch (NoSuchAlgorithmException e) {             e.printStackTrace();         } catch (NoSuchPaddingException e) {             e.printStackTrace();         } catch (InvalidKeyException e) {             e.printStackTrace();         } catch (IllegalBlockSizeException e) {             e.printStackTrace();         } catch (BadPaddingException e) {             e.printStackTrace();         } catch (NoSuchProviderException e) {             // TODO Auto-generated catch block             e.printStackTrace();         } catch (Exception e) {             // TODO Auto-generated catch block             e.printStackTrace();         }         return null;     }   } import java.nio.charset.Charset; import java.util.Arrays;   public class WxPKCS7Encoder {      private static final Charset CHARSET = Charset.forName("utf-8");         private static final int BLOCK_SIZE = 32;

 

public static AlgorithmParameters generateIV(byte[] iv) throws Exception{

AlgorithmParameters params = AlgorithmParameters.getInstance("AES");

params.init(new IvParameterSpec(iv)); return params;

}         /**          * 获得对明文进行补位填充的字节.          *          * @param count 需要进行填充补位操作的明文字节个数          * @return 补齐用的字节数组          */         public static byte[] encode(int count) {             // 计算需要填充的位数             int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);             if (amountToPad == 0) {                 amountToPad = BLOCK_SIZE;             }             // 获得补位所用的字符             char padChr = chr(amountToPad);             String tmp = new String();             for (int index = 0; index < amountToPad; index++) {                 tmp += padChr;             }             return tmp.getBytes(CHARSET);         }         /**          * 删除解密后明文的补位字符          *          * @param decrypted 解密后的明文          * @return 删除补位字符后的明文          */         public static byte[] decode(byte[] decrypted) {             int pad = decrypted[decrypted.length - 1];             if (pad < 1 || pad > 32) {                 pad = 0;             }             return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);         }         /**          * 将数字转化成ASCII码对应的字符,用于对明文进行补码          *          * @param a 需要转化的数字          * @return 转化得到的字符          */         public static char chr(int a) {             byte target = (byte) (a & 0xFF);             return (char) target;         }   } 处理业务逻辑

package com.qujiali.service;   import javax.annotation.Resource;   import java.util.HashMap; import java.util.Map; import java.util.Set;   import org.apache.commons.codec.binary.Base64; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate;   import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.qujiali.mapper.TMemberMapper; import com.qujiali.model.TMember;   import top.qujiali.core.Constants; import top.qujiali.core.base.BaseService; import top.qujiali.core.util.AES; import top.qujiali.core.util.SecurityUtil; import top.qujiali.core.util.WxPKCS7Encoder;   /**  * 微信小程序授权登陆  *   * @author ydl  * @date 2018年7月3日  */ @Service public class WxloginService extends BaseService<TMember> {           public Map wxLogin(String Code, String encryptedData, String iv) {         try {                 //用map来封装想给前端返回的数据             Map map = new HashMap();             // 微信服务器的接口,其实就是微信官方文档上面的那一串url地址             String url = Constants.WECHATURLHEAD + Code + Constants.WECHATURLEDN;             // 服务端请求URL需要的Spring对象             RestTemplate restTemplate = new RestTemplate();             // 调用请求url             ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, String.class);             if (responseEntity != null && responseEntity.getStatusCode() == HttpStatus.OK) {                 // 拿到消息体                 String sessionData = responseEntity.getBody();                 JSONObject json = JSON.parseObject(sessionData);                 // 1.sessionkey取消空格这里就是特别坑的一个地方                 String data = encryptedData.replaceAll(" ", "+");                 String ivstr = iv.replaceAll(" ", "+");                 String sessionkey = json.get("session_key").toString();                 // 2.openId 取消空格补充"+"                 String openId = json.get("openid").toString();                 // 3、对encryptedData加密数据进行AES解密                 AES aes = new AES();                 byte[] resultByte = aes.decrypt(Base64.decodeBase64(data), Base64.decodeBase64(sessionkey),                         Base64.decodeBase64(ivstr));                 // 4.保存数据到服务器                 if (null != resultByte && resultByte.length > 0) {                     String userInfo = new String(WxPKCS7Encoder.decode(resultByte));                     JSONObject wxinfo = JSON.parseObject(userInfo);                     Set<String> keySet = wxinfo.keySet();                     for (String key : keySet) { //这里拿到key 和value就可以获取到解密后的所有数据了你可以做你自己的业务了,保存unioId或者是openId自己处理                     }                   }                 }             return map;         } catch (Exception e) {             throw new RuntimeException("微信登陆发生异常");         }     } }

第三种方式: 无需导入第三方jar

一、前端需传递参数  iv  encryptedData signature  rawData

package com.platform.entity;

import java.io.Serializable;


/**
 * @author zwr
 * @email 1064562445@qq.com
 * @date 2017-08-15 08:03:41
 */
public class FullUserInfo implements Serializable {
    private static final long serialVersionUID = 1L;

    //errMsg
    private String errMsg;
    //rawData
    private String rawData;

    //encryptedData
    private String encryptedData;
    //iv
    private String iv;
    //signature
    private String signature;

}
/**
 * 登录
 */
@ApiOperation(value = "登录")
@IgnoreAuth
@RequestMapping("/app/loginWeChat")
@Transactional(rollbackFor = Exception.class)
public Object loginByWeixin() {
    JSONObject jsonParam = this.getJsonRequest();
    logger.info("***请求参数=" + jsonParam.toString());
    FullUserInfo fullUserInfo = null;
    String code = "";
    if (!StringUtils.isNullOrEmpty(jsonParam.getString("code"))) {
        code = jsonParam.getString("code");
    }
    if (null != jsonParam.get("data")) {
        fullUserInfo = jsonParam.getObject("data", FullUserInfo.class);
    }
    if (null == fullUserInfo) {
        return R.error("登录失败");
    }
    Map<String, Object> resultObj = new HashMap<>();
  
    //获取openid //小程序appid修改做修改  // logger.info("》》》组合token为:" + requestUrl);
    String requestUrl = ApiUserUtils.getWebAccess(code);
    //通过自定义工具类组合出小程序需要的登录凭证 code //System.out.println(sessionData.getString("openid"));
    JSONObject sessionData = CommonUtil.httpsRequest(requestUrl, "GET", null);

    if (null == sessionData || StringUtils.isNullOrEmpty(sessionData.getString("openid"))) {
        return R.error("登录失败");
    }
    String uuid ="";
    if(StringUtils.isNullOrEmpty(sessionData.getString("unionid"))){
        uuid=  sessionData.get("unionid").toString();
    }

}

工具类  

wx.webAccessTokenhttps = https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code
package com.platform.util;

import com.platform.utils.ResourceUtil;

/**
 * 作者: @author zwr <br>
 * 时间: 2017-08-11 08:58<br>
 * 描述: ApiUserUtils <br>
 */
public class ApiUserUtils {

    //替换字符串
    public static String getCode(String APPID, String REDIRECT_URI, String SCOPE) {
        return String.format(ResourceUtil.getConfigByName("wx.getCode"), APPID, REDIRECT_URI, SCOPE);
    }

    //替换字符串 验证appid和secret的正确性
    public static String getWebAccess(String CODE) {
        return String.format(ResourceUtil.getConfigByName("wx.webAccessTokenhttps"),
                ResourceUtil.getConfigByName("wx.appId"),
                ResourceUtil.getConfigByName("wx.secret"),
                CODE);
    }

    //替换字符串
    public static String getUserMessage(String access_token, String openid) {
        return String.format(ResourceUtil.getConfigByName("wx.userMessage"), access_token, openid);
    }
}
package com.platform.util;

import com.alibaba.fastjson.JSONObject;
import com.platform.utils.CharUtil;
import com.platform.utils.DateUtils;
import com.platform.utils.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CommonUtil {
    /**
     * 发送https请求
     *
     * @param requestUrl    请求地址
     * @param requestMethod 请求方式(GET、POST)
     * @param outputStr     提交的数据
     * @return JSONObject(通过JSONObject.get ( key)的方式获取json对象的属性值)
     */
    public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        try {
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = {new MyX509TrustManager()};
            /*
                该处不对ssl证书进行验证,以免测试不通过
             */
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            //从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();
            URL url = new URL(requestUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ssf);

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求方式(GET/POST)
            conn.setRequestMethod(requestMethod);

            // 当outputStr不为null时向输出流写数据
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }

            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            jsonObject = JSONObject.parseObject(buffer.toString());
        } catch (ConnectException ce) {
            log.error("连接超时:{}", ce);
        } catch (Exception e) {
            log.error("https请求异常:{}", e);
        }
        return jsonObject;
    }

}

转载注明出处,掌声送给社会人

标签: ydl连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台