若是用户在微信客户端中访问第三方网页,公众号能够经过微信网页受权机制,来获取用户基本信息,进而实现业务逻辑。json
关于网页受权的两种scope的区别说明api
一、以snsapi_base为scope发起的网页受权,是用来获取进入页面的用户的openid的,而且是静默受权并自动跳转到回调页的。用户感知的就是直接进入了回调页(每每是业务页面)微信
二、以snsapi_userinfo为scope发起的网页受权,是用来获取用户的基本信息的。但这种受权须要用户手动赞成,而且因为用户赞成过,因此无须关注,就可在受权后获取该用户的基本信息。 app
三、用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注后事件推送后,才能根据用户OpenID来获取用户基本信息。这个接口,包括其余微信接口,都是须要该用户(即openid)关注了公众号后,才能调用成功的。 微信公众平台
关于网页受权access_token和普通access_token的区别dom
一、微信网页受权是经过OAuth2.0机制实现的,在用户受权给公众号后,公众号能够获取到一个网页受权特有的接口调用凭证(网页受权access_token),经过网页受权access_token能够进行受权后接口调用,如获取用户基本信息; ide
二、其余微信接口,须要经过基础支持中的“获取access_token”接口来获取到的普通access_token调用。 ui
关于特殊场景下的静默受权this
一、上面已经提到,对于以snsapi_base为scope的网页受权,就静默受权的,用户无感知;
二、对于已关注公众号的用户,若是用户从公众号的会话或者自定义菜单进入本公众号的网页受权页,即便是scope为snsapi_userinfo,也是静默受权,用户无感知。
具体而言,网页受权流程分为四步:
一、引导用户进入受权页面赞成受权,获取code
二、经过code换取网页受权access_token(与基础支持中的access_token不一样)
三、若是须要,开发者能够刷新网页受权access_token,避免过时
四、经过网页受权access_token和openid获取用户基本信息(支持UnionID机制)
以上摘自官方开发文档。点击这里查看。
我的理解就是一旦用户在微信公众平台上进行第三方页面跳转,均会触发认证。如在公众号内经过点击菜单跳转网页(此状况通常在建立菜单对应的url就会引导以下地址)或者是
在点击图文消息时(须要设置对应的url)。
此时开发者须要引导用户打开以下地址来获取code
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 若提示“该连接没法访问”,请检查参数是否填写错误,是否拥有scope参数对应的受权做用域权限。
如须要页面跳转则可经过设置此处的 redirect_uri 来实现。
下面是经过回调的方式,让腾讯回调咱们本身的控制器来获取所须要的信息。
经过code获取openid
@RequestMapping(value="/authRedirect.do",method = RequestMethod.GET) public Object authRedirect(@RequestParam(required = true) String state,Model model, @RequestParam(required = true) String code, HttpServletRequest request, HttpServletResponse response, RedirectAttributes redirectAttributes) throws Exception { String redirectUrl=""; logger.info("---------------微信受权成功回调开始--------------"); try { if (StringUtils.isNotBlank(code)) { String oauth_access_token_url = this.wxPropertiesBean.getProperties("wxpt").getProperty("oauth_access_token_url"); String sysytemAppid = (String) wxPropertiesBean.getProperties("system").get("system_appid"); Map config = this.wxMpService.queryWxAccountByCode(sysytemAppid); Map<String,Object> urlParams = new HashMap<String,Object>(); urlParams.put("appid", config.get("account_appid")); urlParams.put("secret", config.get("account_appsecret")); urlParams.put("code", code); String url = HttpUtil.getUrl(oauth_access_token_url, urlParams); WxApiResult apiResult = HttpUtil.httpsRequest(url, "GET", null); Map result = HttpUtil.getCommonResult(apiResult); String openid = (String) result.get("openid"); if(StringUtils.isNotBlank(openid)){ request.getSession().setAttribute("openid", openid); } } //查询自定义菜单信息 Map channel = this.wxMpService.queryWxChannelByCode(state); String relaPath = this.wxPropertiesBean.getProperties("system").getProperty(state); if(channel!=null&&channel.get("link_url")!=null){ redirectUrl = (String) channel.get("link_url"); }else if(relaPath!=null){ String protocol = (String) config.get("protocol"); String domain = (String) config.get("domain"); redirectUrl = protocol + domain + relaPath; }else{ String protocol = (String) config.get("protocol"); String domain = (String) config.get("domain"); redirectUrl = protocol + domain; } if(redirectUrl.indexOf("?") > -1) { redirectUrl = redirectUrl +"&v="+Math.random(); }else{ redirectUrl = redirectUrl +"?v="+Math.random(); } } } catch (Exception e) { logger.error(e.getMessage()); throw new Exception("系统没法完成请求,错误信息:"+e.getMessage()); } return "redirect:" + redirectUrl; }
/** * 发送https请求 * @param requestUrl 请求地址 * @param requestMethod 请求方式(GET、POST) * @param outputStr 提交的数据 * @return JSONObject(经过JSONObject.get(key)的方式获取json对象的属性值) */ public static WxApiResult httpsRequest(String requestUrl, String requestMethod, String outputStr) { WxApiResult message = new WxApiResult(); try { TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setSSLSocketFactory(ssf); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); conn.setRequestMethod(requestMethod); if (null != outputStr) { OutputStream outputStream = conn.getOutputStream(); outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } InputStream inputStream = conn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; StringBuffer buffer = new StringBuffer(); while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } if(conn.getResponseCode()==conn.HTTP_OK){ message.setCode(0); message.setContent(buffer.toString()); }else{ message.setCode(-1); message.setContent("获取返回状态不对,返回状态为:"+conn.getResponseCode()); } // 释放资源 bufferedReader.close(); inputStreamReader.close(); inputStream.close(); inputStream = null; conn.disconnect(); } catch (ConnectException ce) { log.error("链接超时:{}", ce); message.setCode(-1); message.setContent(ce.getMessage()); } catch (Exception e) { log.error("https请求异常:{}", e); message.setCode(-1); message.setContent(e.getMessage()); } return message; }
如需获取用户信息只需经过上述代码中获取到的openid和access_token获取便可。
@Override public String getCustImg(HttpServletRequest request, Map<String, Object> param){ try{ String openid = (String) request.getSession().getAttribute("openid"); String oauth_access_token_url = "https://api.weixin.qq.com/sns/userinfo"; String accessToken = wxTokenComp.getAccessToken(); Map urlParams = new HashMap(); urlParams.put("openid",openid); urlParams.put("access_token",accessToken); urlParams.put("lang","zh_CN"); String url = HttpUtil.getUrl(oauth_access_token_url, urlParams); WxApiResult apiResult = HttpUtil.httpsRequest(url, "GET", null); Map rstMap = HttpUtil.getCommonResult(apiResult); }catch(Exception e){ e.printStackTrace(); } return rstMap.get("headimgurl");
}