最近公司要求开发一个涉及到微信公众号网页授权开发的功能,于是花了一点时间学习了一下,下面总结一下这一块的技术涉及以及开发过程中遇到的一些问题以及解决方案:
1、微信官方API链接:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
2、官方技术总结很简洁明了:
在你写代码之前的准备工作:在你的公众号里边配置授权回调域名。
1、在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头;
2、授权回调域名配置规范为全域名,比如需要网页授权的域名为:www.qq.com,配置以后此域名下面的页面 http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以进行OAuth2.0鉴权。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com无法进行OAuth2.0鉴权
1)、获取Code;只能用一次,或者5分钟自动过期。
2)、用code去换取access_token(这个access_token跟普通的不一样,具体想了解官方api有说明,这里不详细说。)
3)、用access_token和openid去获取用户的微信用户的具体信息(头像,昵称等),时间是7200秒内有效,当然,你也可以刷新再次获取。
OK,上面第一步获取code,https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect,其中APPID是公众号的appid,redirect_uri是自己的系统给微信回调用的链接(可以是前台页面地址,也可以是后台接口,但是前面的域名一定是上面已经配置到了公众号授权配置里的),scope是标识你要获取微信用户信息的类型,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 ),state可以是你自己的带过去的一个参数,微信侧会给你原样带回来,其他固定。返回值就是一个code的string串。
第二步用code去换取access_token,https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code,其中 appid和secret都是公众号的配置,一般不会变动,code即为第一步获取到的code值,其他固定。返回值是一个json串,{ "access_token":"ACCESS_TOKEN","expires_in":7200,"refresh_token":"REFRESH_TOKEN","openid":"OPENID","scope":"SCOPE" },其中 access_token和openid即为第三步要用的值,refresh_token则是一个链接(类似:https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN),当access_token超时后,可以使用refresh_token进行刷新。
第三步则是用access_token和openid去获取用户的信息,https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN,返回值是json串,{ "openid":" OPENID"," nickname": NICKNAME,"sex":"1","province":"PROVINCE","city":"CITY","country":"COUNTRY","headimgurl": "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/4","privilege":[ "PRIVILEGE1" "PRIVILEGE2" ],"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"},nickname和headimg即为用户昵称和头像,当然还包括了一些其他的用户信息。
接下来说自己开发中遇到的问题:
1.首先,是第二步和第三步中去访问微信调用微信侧的时候,一直报无法连接到该接口。
原因:我自己最大的问题是,由于测试环境没有开通对外某个域名对应的ip地址的443端口的访问权限。其次,也要保证是https的请求。
解决方法:申请网络管理侧开通端口访问权限;用X509TrustManager去获取一个可信任https的请求。
代码(参考网上代码写的):
/**
* 获取可信任https链接,以避免不受信任证书出现peer not authenticated异常
*
* @param base
* @return
*/
public static HttpClient wrapClient(HttpClient base,String logUniqueFlag) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("https", 443, ssf));
ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(registry);
log.info("{}-获取到了可信任的https链接!",logUniqueFlag);
return new DefaultHttpClient(mgr, base.getParams());
} catch (Exception ex) {
log.error("{}-获取可信任https链接发生异常。ex={}", logUniqueFlag,ex);
return null;
}
}
具体发起请求的时候的调用:
client = new DefaultHttpClient();
if(sendUrl.startsWith("https")){
client = wrapClient(client,logUniqueFlag);
}
2.去获取access-token和openid的时候,一直报40125的错误,即:{"errcode":40125,"errmsg":"invalid appsecret, view more at http:\/\/t.cn\/LOEdzVq, hints: [ req_id: kL8J90219sg58 ]"},看errmsg提示,是公众号的app secret报错了,但是我的公众号的appid,appno,app secret一直被另外两个系统在用着,不可能报错才对,于是网上各种找资料,最终网上大部分人都是说重置一下app secret,于是只好找了一个时间,将其他两个系统的app secre也一起更新了,一直到我写这篇文章为止,也没有找到其他的解决方案,如果有人知道其他方法,还请留言给我,非常感谢。
本文章基本都是搬运,没有什么自己创新的东西,权当是当一个开发记录日志,也为以后可能再次使用当一个参考。