发表日期:2019-08 文章编辑:小灯 浏览次数:609
说到这里真的很想吐槽这个微信官方文档了。结合后端开发语言的Demo中竟然没有java不想说了。截至到2018年7月9日。微信官方api依旧没有!呵呵呵呵呵呵,不多BB接下来给小伙伴们分享一下获取unioId的方法
一、首先清楚原理
绑定了开发者帐号的小程序,可以通过下面3种途径获取UnionID。
调用接口wx.getUserInfo,从解密数据中获取UnionID。注意本接口需要用户授权,请开发者妥善处理用户拒绝授权后的情况。以上是微信小程序官方api其中后两种方式,表示看不懂,我们身为程序员就使用第一种方法
有的同学可能会说为什么我调用了wx.getUserInfo只能获取到基本的一些微信用户的信息,根本没有什么openId以及unionId?
因为。你需要在调用wx.login()成功后的回调函数中在调用wx.getUserInfo,你就会获得包含openId以及unionId的加密数据
不懂的同学看下面的小程序代码就明白了。
打印一下你拿到的数据,你就会发现这些数据全都是加密数据,我们必须用后端实现解密,才能拿到有价值的数据
二 、用自己的理解方式去做登陆
为什么要这么说,因为按照微信小程序的api只需要从小程序获得code用后端处理就能返回openId和session_key
这种方法很蠢。
下面我来解释一下我做微信登陆的方式
首先确定参数:
小程序端传递的数据为
code:微信小程序发送给我们后端的登陆验证code
encrypteData:包含unioId等敏感信息
iv:加密算法的初始向量
后端处理参数(非常重要!以java为例子)
这个地方有坑下面我来说一下传递这三个参数的时候会出现什么问题
code传递的时候,不会出问题,但是encrypteData和iv的传递的时候,因为它的加密算法原因,导致这两条密文会填充一些"+"符号。但是"+"在URL传递参数的时候,会被解析成空格 所以在后端处理参数的时候先替换掉所有参数的空格,用string.replaceAll(" ","+"); 将"+"符号还原回来,再进行业务处理。
三、解密操作
解密操作需要两个类。CSDN上面的论坛帖子都是一个不完全的流程瞎转载到处踩坑。本人踩遍无数次的坑之后呢,决定一定要把完整版的分享给大家,话不多说上工具类!
AES类
注意这个类!这行代码,你必须要用BC算法才可以。
Cipher cipher = Cipher.getInstance(ALGORITHM,"BC");
然后注意一下这个,如果你的项目框架中有这个类,一定要让他加载的时候最先加载。如果没有的话,你就在每次加密解密之前创建这个对象就好了import org.bouncycastle.jce.provider.BouncyCastleProvider;
在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;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; }}
第二个类WxPKCS7Encoder
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;/** * 获得对明文进行补位填充的字节. * * @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;}}
三、怎么处理自己的业务逻辑
下面解释一下为什么我要写成这样的service业务逻辑,大家看完之后就会明白了~
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日 */@Servicepublic 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();// 调用请求urlResponseEntity<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("微信登陆发生异常");}}}
好了~有不懂的小伙伴可以评论问我。
日期:2019-11 浏览次数:4788
日期:2019-11 浏览次数:11211
日期:2019-11 浏览次数:3652
日期:2019-11 浏览次数:4560
日期:2019-11 浏览次数:4659
日期:2019-11 浏览次数:6330
日期:2019-11 浏览次数:4580
日期:2019-11 浏览次数:15028
日期:2019-11 浏览次数:3927
日期:2019-11 浏览次数:5699
日期:2019-11 浏览次数:4534
日期:2019-11 浏览次数:3866
日期:2019-11 浏览次数:9627
日期:2019-11 浏览次数:7538
日期:2019-11 浏览次数:4229
日期:2019-11 浏览次数:3622
日期:2019-11 浏览次数:8165
日期:2019-11 浏览次数:3876
日期:2019-11 浏览次数:4050
日期:2019-11 浏览次数:4120
日期:2019-11 浏览次数:3685
日期:2019-11 浏览次数:4268
日期:2019-11 浏览次数:9452
日期:2019-11 浏览次数:4469
日期:2019-11 浏览次数:4463
日期:2019-11 浏览次数:4045
日期:2019-11 浏览次数:11364
日期:2019-11 浏览次数:6660
日期:2019-11 浏览次数:6920
日期:2019-11 浏览次数:4272
Copyright ? 2013-2018 Tadeng NetWork Technology Co., LTD. All Rights Reserved.