java后端实现微信公众号开发---服务号和订阅号的坑

java后端实现微信公众号开发—服务号和订阅号的坑
微信的授权,前后端都可以发起,本人这次是试用后端实现

前提----本人最近改造公司历史久远的h5系统

需求:首先是在登录时要发起授权,原系统没有授权操作,另外在一套代码里实现两个公众号,一个是订阅号,一个是服务号,订阅号只能做登录注册查看功能,而服务号的就是正常功能

订阅号的坑

微信对于订阅号的概念是:用于运营人员给客户发送文章的功能
订阅号不支持微信授权!!!
当时一直很奇怪,日志打印信息记录的appid明明成功区分了订阅号和服务号,为什么订阅号就是不能发起授权…
研究了很久,突然想起来看到过有个帖子说,订阅号授权微信没开放
然后就到了微信开发者平台看,但是账号是客户给的,也没给我们绑定开发者账号,于是leader试图联系客服…然而腾讯客服有这么容易联系上吗?
最后由于时间紧迫放弃了使用订阅号获取授权(主要是订阅号授权也没太大作用,就是显示用户昵称,信息)

服务号h5开发

首先查看微信官方给的文档:
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
话说18年有协助朋友开发过一个小程序,页面主要由前端实现,当时前端同事遇到过一个问题,某天突然就不能显示用户昵称什么的了,排查了很久,最后发现是微信改规则了,想要获取用户信息,必须发起授权由用户同意…
本人这次后端发起授权的步骤:

  1. 判断本次用户点击页面是否有cookies和redis缓存(原系统有自动登录功能,cookies保存有效期为1天,其中cookies存放用户openid,在根据cookies从redis中取值)
  2. 如果cookies无效,检查请求url参数中有无code,调用微信outh2方法发起授权,获取code:
	//必须给定一个回调地址
	@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

你可能感兴趣的:(java后端)