微信公眾號java開發沉澱(四)獲取使用者資訊
關注公眾號後,公眾號可獲得關注者的OpenID(加密後的微訊號,每個使用者對每個公眾號的OpenID是唯一的。對於不同公眾號,同一使用者的openid不同)。公眾號可通過OpenID獲取使用者基本資訊,包括暱稱、頭像、性別、所在城市、語言和關注時間。
如果開發者有在多個公眾號,或在公眾號、移動應用之間統一使用者帳號的需求,需要前往微信開放平臺(open.weixin.qq.com)繫結公眾號後,才可利用UnionID機制來滿足上述需求。
一個微信使用者對一個公眾號OpenID 是唯一的。一個微信使用者對同一個微信開放平臺UnionID是唯一的。
獲取OpenID前,先要獲取code
在微信裡面引導關注者開啟如下頁面(測試方便起見可以直接把url當成普通訊息通過檔案傳輸助手發到微信上,然後直接點這個連結,效果一樣):
如果使用者同意授權,頁面將跳轉至 redirect_uri?code=CODE&state=STATE 就這樣code自動生成了。會帶進重定向的url的後面引數中。
redirect_uri 是我們java專案提供的一個URL,接收兩個引數:code 和 state。注意redirect_uri 需要URL編碼。
url 編碼以後是 https%3a%2f%2f60cc9d13.ngrok.io%2fwx%2fapi%2fuserInfo
把這個url發到微信,點選,就可以直接訪問了。下面有程式碼和tomcat日誌。
根據code獲取OpenId
訪問
https://api.weixin.qq.com/sns/oauth2/access_token?appid=${APPID}&secret=${APPSECRET}&code=${CODE}&grant_type=authorization_code
返回包含openId的json物件。
獲取access_token
訪問
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}
返回包含accessToken的json物件
獲取使用者資訊
訪問
https://api.weixin.qq.com/cgi-bin/user/info?access_token=${ACCESS_TOKEN}&openid=${OPENID}&lang=zh_CN
返回使用者資訊,注意如果使用了開放平臺,才有unionid。否則unionid為null.
程式碼demo,簡單起見所有東西都放一個類裡了.
不要亂用我的appId和SECRET
package com.tsing.wechat.controller;
import com.alibaba.fastjson.JSON;
import com.tsing.wechat.model.AccessToken;
import com.tsing.wechat.model.WeChatUserInfo;
import com.tsing.wechat.model.WebToken;
import com.tsing.wechat.utils.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrSubstitutor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/api")
public class WxUserInfoController {
public static final String APP_ID = "APPID";
public static final String APP_ID_VALUE = "wx5087e91fe1430b1d";
public static final String APP_SECRET = "APPSECRET";
public static final String APP_SECRET_VALUE = "*****";
public static final String CODE = "CODE";
public static final String ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}";
private static final String ACCESS_TOKEN_CODE = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=${APPID}&secret=${APPSECRET}&code=${CODE}&grant_type=authorization_code";
private static final String USER_INFO = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=${ACCESS_TOKEN}&openid=${OPENID}&lang=zh_CN";
/**
* 根據code獲取網頁授權使用者的openid
*/
@RequestMapping(value = "/userInfo")
public WeChatUserInfo getUserInfo(@RequestParam String code, @RequestParam String state) {
String openId = getWebAccessToken(APP_ID_VALUE, APP_SECRET_VALUE, code);
log.debug("根據code=" + code + "獲取openId值為:" + openId);
String accessToken = getAccessToken(APP_ID_VALUE, APP_SECRET_VALUE);
WeChatUserInfo userInfo = getWeChatUserInfo(accessToken, openId);
log.info("使用者資訊:{}", userInfo);
return userInfo;
}
public WeChatUserInfo getWeChatUserInfo(String accessToken, String openId) {
Map<String, String> map = new HashMap<>();
map.put("ACCESS_TOKEN", accessToken);
map.put("OPENID", openId);
String usrInfoUrl = urlReplace(USER_INFO, map);
log.info("獲取到的使用者資訊url:{}", usrInfoUrl);
String useStr = HttpUtils.doGet(usrInfoUrl);
log.info("獲取到的使用者資訊為:{}", useStr);
return JSON.parseObject(useStr, WeChatUserInfo.class);
}
public String getWebAccessToken(String appId, String secret, String code) {
Map<String, String> map = new HashMap<>();
map.put(APP_ID, appId);
map.put(APP_SECRET, secret);
map.put(CODE, code);
String url = urlReplace(ACCESS_TOKEN_CODE, map);
log.info("獲取網頁token的URL:{}", url);
String res = HttpUtils.doGet(url);
log.info("獲取網頁token的返回:{}", res);
WebToken token = JSON.parseObject(res, WebToken.class);
return token.getOpenId();
}
public String getAccessToken(String appId, String secret) {
Map<String, String> map = new HashMap<>();
map.put(APP_ID, appId);
map.put(APP_SECRET, secret);
String url = urlReplace(ACCESS_TOKEN, map);
String res = HttpUtils.doGet(url);
log.info("獲取token返回:{}", res);
AccessToken token = JSON.parseObject(res, AccessToken.class);
return token.getAccessToken();
}
/**
* 將URL中的模板引數用實際值替換
*
* @param url url
* @param parms 引數
* @return 替換引數後的url
*/
public static String urlReplace(String url, Map<String, String> parms) {
if (StringUtils.isNotBlank(url) && null != parms) {
StrSubstitutor strsub = new StrSubstitutor(parms);
url = strsub.replace(url);
}
return url;
}
}
日誌,因為只是一個測試公眾號,沒有繫結微信開放平臺,所以最後一行日誌大的unionid=null
2018-10-16 10:23:04.467 INFO [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getWebAccessToken:71 -獲取網頁token的URL:https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx5087e91fe1430b1d&secret=b6428efc6c87d5b8cd29bc757407d8e6&code=07113uKn1wh6si0TCtKn1YpsKn113uK7&grant_type=authorization_code
2018-10-16 10:23:04.669 INFO [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getWebAccessToken:73 -獲取網頁token的返回:{"access_token":"14_wDfP5QFeN-R8fhq8WgZRuapJGnQSz5lQrI4cOqc6CDAuqJvaeO-FBKJV6f2b6EEUVy-a3TNTBgBDky00M6okPA","expires_in":7200,"refresh_token":"14_mQTvjt1tglGSN82bqxa2XKqRmqdI0slBKGzLkOUlpzR-rPOIwrzMT3HWbgFp3US1zoafY5dF_I4O-yG2spvGgQ","openid":"o-7aj0hBDfVEzsK2P_F9U-IwosZ4","scope":"snsapi_userinfo"}
2018-10-16 10:23:04.670 DEBUG [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getUserInfo:47 -根據code=07113uKn1wh6si0TCtKn1YpsKn113uK7獲取openId值為:o-7aj0hBDfVEzsK2P_F9U-IwosZ4
2018-10-16 10:23:04.854 INFO [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getAccessToken:84 -獲取token返回:{"access_token":"14_xEbh6Hq5U0MXjAmlEUY88dcm5BrRB7lPnLgcgiIzZE9zkOsUsry1Ms57hKJGIqmXKwakgn10V4MqtGx_zCVrHW3HRpjCQiY6zji2itWpgvN3kNBS1NAJAUK5jNjpHTrLuOisDIIH24L5yZbHNITdAGAXSD","expires_in":7200}
2018-10-16 10:23:04.854 INFO [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getWeChatUserInfo:59 -獲取到的使用者資訊url:https://api.weixin.qq.com/cgi-bin/user/info?access_token=14_xEbh6Hq5U0MXjAmlEUY88dcm5BrRB7lPnLgcgiIzZE9zkOsUsry1Ms57hKJGIqmXKwakgn10V4MqtGx_zCVrHW3HRpjCQiY6zji2itWpgvN3kNBS1NAJAUK5jNjpHTrLuOisDIIH24L5yZbHNITdAGAXSD&openid=o-7aj0hBDfVEzsK2P_F9U-IwosZ4&lang=zh_CN
2018-10-16 10:23:05.017 INFO [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getWeChatUserInfo:61 -獲取到的使用者資訊為:{"subscribe":1,"openid":"o-7aj0hBDfVEzsK2P_F9U-IwosZ4","nickname":"_captain","sex":1,"language":"zh_CN","city":"杭州","province":"浙江","country":"中國","headimgurl":"http:\/\/thirdwx.qlogo.cn\/mmopen\/9RibwCfvUfQNnmNiarD2S8A8YNHC4IGOLgzSBRMaeyDSG0JBpmHXZLNOxqJypjnib8vFkDUCbn5IicLvL4ibDps5LvzAEZs5FjQiaib\/132","subscribe_time":1539600947,"remark":"","groupid":0,"tagid_list":[],"subscribe_scene":"ADD_SCENE_QR_CODE","qr_scene":0,"qr_scene_str":""}
2018-10-16 10:23:05.038 INFO [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getUserInfo:50 -使用者資訊:WeChatUserInfo(openid=o-7aj0hBDfVEzsK2P_F9U-IwosZ4, subscribe=1, subscribeTime=null, nickName=_captain, sex=1, country=中國, province=浙江, city=杭州, language=zh_CN, headImgUrl=http://thirdwx.qlogo.cn/mmopen/9RibwCfvUfQNnmNiarD2S8A8YNHC4IGOLgzSBRMaeyDSG0JBpmHXZLNOxqJypjnib8vFkDUCbn5IicLvL4ibDps5LvzAEZs5FjQiaib/132, unionid=null)
不要亂用我的appId和SECRET