微信公众号java开发沉淀(四)获取用户信息


​ 关注公众号后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的。对于不同公众号,同一用户的openid不同)。公众号可通过OpenID获取用户基本信息,包括昵称、头像、性别、所在城市、语言和关注时间。

​ 如果开发者有在多个公众号,或在公众号、移动应用之间统一用户帐号的需求,需要前往微信开放平台(open.weixin.qq.com)绑定公众号后,才可利用UnionID机制来满足上述需求。

​ 一个微信用户对一个公众号OpenID 是唯一的。一个微信用户对同一个微信开放平台UnionID是唯一的。

获取OpenID前,先要获取code

在微信里面引导关注者打开如下页面(测试方便起见可以直接把url当成普通消息通过文件传输助手发到微信上,然后直接点这个链接,效果一样):

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

如果用户同意授权,页面将跳转至 redirect_uri?code=CODE&state=STATE 就这样code自动生成了。会带进重定向的url的后面参数中。

redirect_uri 是我们java项目提供的一个URL,接收两个参数:code 和 state。注意redirect_uri 需要URL编码。

例如,我现在提供的接口是 https://60cc9d13.ngrok.io/wx/api/userInfo

url 编码以后是 https%3a%2f%2f60cc9d13.ngrok.io%2fwx%2fapi%2fuserInfo

替换后 https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx9614d94b5cb85921&redirect_uri=http%3A%2F%2F60cc9d13.ngrok.io%2Fwx%2Fapi%2FuserInfo&response_type=code&scope=snsapi_userinfo&state=#wechat_redirect

把这个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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值