java后端实现微信公众号开发—服务号和订阅号的坑
微信的授权,前后端都可以发起,本人这次是试用后端实现
前提----本人最近改造公司历史久远的h5系统
需求:首先是在登录时要发起授权,原系统没有授权操作,另外在一套代码里实现两个公众号,一个是订阅号,一个是服务号,订阅号只能做登录注册查看功能,而服务号的就是正常功能
微信对于订阅号的概念是:用于运营人员给客户发送文章的功能
订阅号不支持微信授权!!!
当时一直很奇怪,日志打印信息记录的appid明明成功区分了订阅号和服务号,为什么订阅号就是不能发起授权…
研究了很久,突然想起来看到过有个帖子说,订阅号授权微信没开放
然后就到了微信开发者平台看,但是账号是客户给的,也没给我们绑定开发者账号,于是leader试图联系客服…然而腾讯客服有这么容易联系上吗?
最后由于时间紧迫放弃了使用订阅号获取授权(主要是订阅号授权也没太大作用,就是显示用户昵称,信息)
首先查看微信官方给的文档:
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
话说18年有协助朋友开发过一个小程序,页面主要由前端实现,当时前端同事遇到过一个问题,某天突然就不能显示用户昵称什么的了,排查了很久,最后发现是微信改规则了,想要获取用户信息,必须发起授权由用户同意…
本人这次后端发起授权的步骤:
//必须给定一个回调地址
@Override
public String oauth2(String backUrl) {
try {
String serverUrl = URLEncoder.encode(backUrl, "utf-8");
// 检查是否已验证或者验证是否通过
String scope = "snsapi_userinfo";// snsapi_base/snsapi_userinfo
String state = "STATE";
logger.info("serverUrl:" + serverUrl);
//调用的url:
String url= "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+appid+"&redirect_uri="+serverUrl+"&response_type=code&scope=%s&state=%s&connect_redirect=1#wechat_redirect";
try {
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
http.setRequestMethod("GET"); // 必须是get方式请求
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
http.connect();
InputStream is = http.getInputStream();
int size = is.available();
byte[] jsonBytes = new byte[size];
is.read(jsonBytes);
String message = new String(jsonBytes, "UTF-8");
JSONObject demoJson = JSONObject.parseObject(message);
System.out.println("JSON字符串:"+demoJson);
logger.info("JSON字符串:"+demoJson);
String wxCodeUrl = demoJson.getString("url");//这个值不记得了可以看打印的demoJson内容
is.close();
} catch (Exception e) {
logger.error("call oauth2 error",e);
}
logger.info("wxCodeUrl:" + wxCodeUrl);
return wxCodeUrl;//返回微信重定向后带code值的url
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
3, 如果有code,就根据code获取微信用户的openid以及网页授权的access_token,code需要从request请求里取到
注意,微信有两个access_token,一个用于网页授权,一个用于微信基础操作,如分享等,并且这两种授权都只能两个小时获取一次,建议存到redis里,过期时间设置7200秒
公众号的appsecret容易失效,具体可看请求返回的5位数结果码判断问题
@Override
public WxMemberQO getUserOpenId(String code){
logger.info("call getUserOpenId({})",code);
WxMemberQO wxMemberQO=new WxMemberQO();
String openId = null;
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appID+"&secret="+appsecret+"&code="+code+"&grant_type=authorization_code";//这个url链接和参数不能变
try {
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
http.setRequestMethod("GET"); // 必须是get方式请求
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
http.connect();
InputStream is = http.getInputStream();
int size = is.available();
byte[] jsonBytes = new byte[size];
is.read(jsonBytes);
String message = new String(jsonBytes, "UTF-8");
JSONObject demoJson = JSONObject.parseObject(message);
System.out.println("JSON字符串:"+demoJson);
logger.info("JSON字符串:"+demoJson);
openId = demoJson.getString("openid");
String accessToken=demoJson.getString("access_token");
if(StringUtils.isNotBlank(openId) && StringUtils.isNotBlank(accessToken)){
wxMemberQO.setOpenid(openId);
wxMemberQO.setAccessToken(accessToken);
}
is.close();
} catch (Exception e) {
logger.error("call getUserOpenId error",e);
}
return wxMemberQO;
}
4,根据openid和网页授权的access_token获取用户基本信息,如微信昵称,头像,国家,省市信息等
@Override
public WxMemberVO getUserInfo(WxMemberQO wxMemberQO){
logger.info("call getUserInfo({})",JsonUtil.JSON_Bean2String(wxMemberQO));
WxMemberVO wxMemberVO=new WxMemberVO();
if(StringUtils.isNotBlank(wxMemberQO.getAccessToken())){
String url = "https://api.weixin.qq.com/sns/userinfo?access_token="+wxMemberQO.getAccessToken()+"&openid="+wxMemberQO.getOpenid()+"&lang=zh_CN";//这个url链接和参数不能变
try {
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
http.setRequestMethod("GET"); // 必须是get方式请求
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
http.connect();
InputStream is = http.getInputStream();
int size = is.available();
byte[] jsonBytes = new byte[size];
is.read(jsonBytes);
String message = new String(jsonBytes, "UTF-8");
JSONObject demoJson = JSONObject.parseObject(message);
System.out.println("JSON字符串:"+demoJson);
String open_ids=demoJson.getString("openid");
if (StringUtils.isNotBlank(open_ids)) {
wxMemberVO.setNickname(demoJson.getString("nickname"));
wxMemberVO.setHeadimgurl(demoJson.getString("headimgurl"));
wxMemberVO.setSex(demoJson.getString("sex"));
wxMemberVO.setCity(demoJson.getString("city"));
wxMemberVO.setCountry(demoJson.getString("country"));
wxMemberVO.setProvince(demoJson.getString("province"));
wxMemberVO.setPrivilege(demoJson.getString("province"));
wxMemberVO.setOpenid(open_ids);
} else {
throw new BizException("","微信返回提示---"+message);
}
is.close();
} catch (Exception e) {
logger.error("call getUserInfo error",e);
}
}else{
wxMemberVO.setErrmsg("授权信息过期!需要重新授权");
return wxMemberVO;
}
return wxMemberVO;
}
5,到这一步就将openid保存到cookies里,并且以这个为键保存到redis,值就存wxMemberVO