微信小程序与微信公众号同一用户登录问题

最近在做微信小程序与微信公众号登录合并的接口。整理相关资料以及个人认识的心得写了这篇文章与大家一起分享。


 首先,简单说下我遇到的问题是我们的程序调用微信小程序得到openid,然后通过openID得到用户的唯一标识,用户得以登录,然而,当我们调用微信公众号也同样的到openid,同一以用户两个不同的openid,不能区分是否为同一用户,然后发现无论调用微信小程序还是微信公众号同一个用户的到unionid是相同的,所以我们就用unionid来区分是否为同一用户。


UnionID机制说明:

如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。


1、对于小程序获取unionid:

 

 我们来看下用户登录小程序时的时序图:


 1、 (JAVA 后台)向微信服务器发起请求附带js_code、appId、secretkey和grant_type参数,以换取用户的openid和session_key(会话密钥)


 用code (前端调用微信接口得到)换取 session_key,openid


 这是一个 HTTPS 接口,开发者服务器使用登录凭证 code 获取 session_key 和 openid。
 其中 session_key 是对用户数据进行加密签名的密钥。为了自身应用安全,session_key 不应该在网络上传输。后台解密用到。


 接口地址:


 https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
 
 请求参数说明:


 1 参数          是否必须    说明
  appid          是    应用唯一标识,在微信开放平台提交应用审核通过后获得
  secret         是    应用密钥AppSecret,在微信开放平台提交应用审核通过后获得
 4 js_code      是    填写第一步获取的code参数
 5 grant_type    是    填authorization_code
 
 Map<String, String> params = new HashMap<String, String>();
 params.put("appid", APPID);
 params.put("secret", SECRET);
 params.put("js_code", "js_Code");
 params.put("grant_type", "authorization_code");
 String openidtoken = HttpClientUtil.invokeGet(https://api.weixin.qq.com/sns/jscode2session, proxy, params,
 utf-8, 60000);


 返回参数:

 参数 说明
 openid  用户唯一标识
 session_key  会话密钥


 2、AES解密核心代码:(包含用户敏感信息的encryptedData信息由前端提供,后台负责解密数据,得到unionId)

[java]  view plain  copy  
  1. public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {  
  2.     initialize();  
  3.     try {  
  4.         Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");  
  5.         Key sKeySpec = new SecretKeySpec(keyByte, "AES");  
  6.   
  7.         cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化   
  8.         byte[] result = cipher.doFinal(content);  
  9.         return result;  
  10.     } catch (NoSuchAlgorithmException e) {  
  11.         e.printStackTrace();    
  12.     } catch (NoSuchPaddingException e) {  
  13.         e.printStackTrace();    
  14.     } catch (InvalidKeyException e) {  
  15.         e.printStackTrace();  
  16.     } catch (IllegalBlockSizeException e) {  
  17.         e.printStackTrace();  
  18.     } catch (BadPaddingException e) {  
  19.         e.printStackTrace();  
  20.     } catch (NoSuchProviderException e) {  
  21.         // TODO Auto-generated catch block  
  22.         e.printStackTrace();  
  23.     } catch (Exception e) {  
  24.         // TODO Auto-generated catch block  
  25.         e.printStackTrace();  
  26.     }  


 3、解密用户信息:

 

[cpp]  view plain  copy  
  1. byte[] resultByte = Aes.decrypt(  
  2.                         Base64.decodeBase64(encryptedData),  
  3.                         Base64.decodeBase64(session_key),  
  4.                         Base64.decodeBase64(ivByte));  
  5.   
  6. if (null != resultByte && resultByte.length > 0) {  
  7.     String userInfo = new String(resultByte, "UTF-8");  
  8.     // 结果转json  
  9.     JsonObject jsonobject = null;  
  10.     try {  
  11.         JsonParser par = new JsonParser();  
  12.         JsonElement jsonelement = par.parse(userInfo);  
  13.         jsonobject = jsonelement.getAsJsonObject();  
  14.     } catch (Exception e) {  
  15.         。。。。。。  
  16.     }  
  17.     // 获取unionid  
  18.     unionID = jsonobject.get("unionId").getAsString() + "";  
  19. }  


 注:String和字节数组之间的转换:


 通过 Base64.decodeBase64(String)就可以得到字节数组。


 通过 String userInfo = new String(resultByte, "UTF-8"); 就得到了想要的String


 4、解密得到的结果:
 加密过程微信服务器完成,解密过程在我们的服务器完成,即由 encryptData 得到如下数据:
 {
 "openId": "OPENID",
 "nickName": "NICKNAME",
 "gender": GENDER,
 "city": "CITY",
 "province": "PROVINCE",
 "country": "COUNTRY",
 "avatarUrl": "AVATARURL",
 "unionId": "UNIONID",
 "watermark":
 {
 "appid":"APPID",
 "timestamp":TIMESTAMP
 }
 }
 5、把得到的unionId与用户的唯一标识绑定在一起,通过标识就可以进行下一步操作,系统不同,操作不同,这里不再详谈。




2、对于公众号获取unionId:


1、先拿code获取网页授权access_token以及openid


 接口地址:


 https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=JSCODE&grant_type=authorization_code
 
 请求参数说明:


  参数          是否必须    说明
  appid          是    应用唯一标识,在微信开放平台提交应用审核通过后获得
  secret         是    应用密钥AppSecret,在微信开放平台提交应用审核通过后获得
  code           是    填写第一步获取的code参数
  grant_type     是    填authorization_code
 
 Map<String, String> params = new HashMap<String, String>();
 params.put("appid", APPID);
 params.put("secret", SECRET);
 params.put("code", "Code");
 params.put("grant_type", "authorization_code");
 String openidtoken = HttpClientUtil.invokeGet(https://api.weixin.qq.com/sns/oauth2/access_token, proxy, params,
 utf-8, 60000);


 返回参数:
 
 "access_token":"ACCESS_TOKEN", 
 "expires_in":7200, 
 "refresh_token":"REFRESH_TOKEN",
 "openid":"OPENID", 
 "scope":"SCOPE" 
 }
 参数             说明
 access_token    接口调用凭证
 expires_in      access_token接口调用凭证超时时间,单位(秒)
 refresh_token   用户刷新access_token
 openid          授权用户唯一标识
 scope           用户授权的作用域,使用逗号(,)分隔.


2、可以看到除access_token外,还可以获得openid,用拿到的access_token和openid获取unionID


 接口地址:


 https://api.weixin.qq.com/sns/userinfo?appid=APPID&secret=SECRET&code=JSCODE&grant_type=authorization_code
 
 请求参数说明:


 1 参数          是否必须    说明
 2 access_token   接口调用凭证
 3 openid          是    授权用户唯一标识
 4 lang            否    一般为固定值zh_CN
 
 Map<String, String> params = new HashMap<String, String>();
 params.put("access_token", access_token);
 params.put("openid", openId);
 params.put("lang", "zh_CN");
 String openidtoken = HttpClientUtil.invokeGet(https://api.weixin.qq.com/sns/userinfo, proxy, params,
 utf-8, 60000);


 在返回值里就包含有用户的unionID。这里不再详述。
 

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值