http://www.cnblogs.com/liliangel/p/6045201.html
微信开发中,经常有这样的需求:获得用户头像、绑定微信号给用户发信息.. 那么实现这些的前提就是授权!
在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名,值得注意的是这里就是直接写全域名,如: www.liliangel.cn。然而我们开发h5中一般用的是二级域名,如:h5.liliangel.cn 也同样在安全回调域名中。
微信更新后,授权页也变化了。其实习惯了绿色的那个经典页面..
以scope=snsapi_userinfo为例,页面加载的时候进入授权方法,首先从缓存获取wxUserInfo对象,如果有说明之前已经授权过,直接进入初始化方法。如果没有,判断url是否包含code,有code说明是进入授权页回调后的页面,那么通过code换取用户信息即可。没有code,即用户第一次进入该页面,引导去授权页,redirect_uri为当前页面地址。
这里有一个授权access_token,切记:授权access_token非全局access_token ,需要使用缓存,这里我使用的redis,具体配置不多说后面写相关配置博文,当然也可以使用ehcache,关于ehcahe配置在我的第一篇博客中有详细介绍。 /** * 根据code 获取授权的token 仅限授权时使用,与全局的access_token不同 * @param code * @return * @throws IOException * @throws ClientProtocolException */ public String getOauthAccessToken(String code) throws ClientProtocolException, IOException{ String data = redisService.get("WEIXIN_SQ_ACCESS_TOKEN"); String rs_access_token = null; String rs_openid = null; String url = WX_OAUTH_ACCESS_TOKEN_URL + "?appid="+WX_APPID+"&secret="+WX_APPSECRET+"&code="+code+"&grant_type=authorization_code"; if (StringUtils.isEmpty(data)) { synchronized (this) { //已过期,需要刷新 String hs = apiService.doGet(url); JSONObject json = JSONObject.parseObject(hs); String refresh_token = json.getString("refresh_token"); String refresh_url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid="+WX_APPID+"&grant_type=refresh_token&refresh_token="+refresh_token; String r_hs = apiService.doGet(refresh_url); JSONObject r_json = JSONObject.parseObject(r_hs); String r_access_token = r_json.getString("access_token"); String r_expires_in = r_json.getString("expires_in"); rs_openid = r_json.getString("openid"); rs_access_token = r_access_token; redisService.set("WEIXIN_SQ_ACCESS_TOKEN", r_access_token, Integer.parseInt(r_expires_in) - 3600); LOGGER.info("Set sq access_token to redis is successful.parameters time:{},realtime",Integer.parseInt(r_expires_in), Integer.parseInt(r_expires_in) - 3600); } }else{ //还没有过期 String hs = apiService.doGet(url); JSONObject json = JSONObject.parseObject(hs); rs_access_token = json.getString("access_token"); rs_openid = json.getString("openid"); LOGGER.info("Get sq access_token from redis is successful.rs_access_token:{},rs_openid:{}",rs_access_token,rs_openid); } return getOauthUserInfo(rs_access_token,rs_openid); } /** * 根据授权token获取用户信息 * @param access_token * @param openid * @return */ public String getOauthUserInfo(String access_token,String openid){ String url = "https://api.weixin.qq.com/sns/userinfo?access_token="+ access_token +"&openid="+ openid +"&lang=zh_CN"; try { String hs = apiService.doGet(url); //保存用户信息 saveWeixinUser(hs); return hs; } catch (IOException e) { LOGGER.error("RestFul of authorization is error.",e); } return null; }
当时赶时间,代码命名较乱。可以看到,我用了一个同步的方法,先从缓存中获取key为WEIXIN_SQ_ACCESS_TOKEN,如果取到了说明没有过期,直接通过httpclient调用微信提供的接口,返回用户信息的字符串给前端。如果没有取到,说明没有或者已经过期,则根据refresh_token刷新access_token,再写缓存,由于access_token拥有较短的有效期,为了保险我这里设置了缓存的失效时间微信给的时间再减一个小时。回过头来看代码发现,上面的逻辑有点点小问题,这样写会导致第一次获取或者缓存失效后第一次获取access_token都会去刷新一次,暂时不影响使用,后面做优化修改 TODO。
参考链接:
微信公众平台官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842&token=&lang=zh_CN
在线接口调试工具:http://mp.weixin.qq.com/debug