在微信客户端中访问第三方网页(自己开发的),需要先通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑。
授权获取openId和用户信息
开发步骤:网页授权 | 微信开放文档
首先要根据前端传来的 code 去获取 openId
/*** 根据code获取openId&access_token*/public GetWxOpenId getOpenIdByCode(String code) {try {String getUrlUri = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code";String url = MessageFormat.format(getUrlUri, projectAppVo.getAppId(), projectAppVo.getAppSecret(), code);JSONObject json = RequestUtil.get(url);if (ObjectUtil.isNotEmpty(json.get("openid"))) {GetWxOpenId wxOpenId = JSON.to(GetWxOpenId.class, json);return wxOpenId;}} catch (Exception e) {e.printStackTrace();}return null;}@Datapublic class GetWxOpenId {@ApiModelProperty(name = "access_token", value = "token")@JsonProperty("access_token")private String accessToken;@ApiModelProperty(name = "expires_in", value = "过期时间")@JsonProperty("expires_in")private Integer expiresIn;@ApiModelProperty(name = "openid", value = "用户openId")private String openid;}
拿到了 openId 后,可以根据 openId 去获取改用户的信息
/*** 获取微信用户信息*/public Map<String, Object> wxUserInfo(String openId) {Map<String, Object> params = new HashMap<>(2);try {String getUrlUri = "https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}&lang=zh_CN";String url = MessageFormat.format(getUrlUri, token, openId);JSONObject json = RequestUtil.get(url);if (ObjectUtil.isNotEmpty(json.get("nickname")) || ObjectUtil.isNotEmpty(json.get("headimgurl"))) {params.put("nickName", json.get("nickname"));params.put("headImgUrl", json.get("headimgurl"));return params;}} catch (Exception e) {e.printStackTrace();}return null;}
JS-SDK使用
微信JS-SDK是微信公众平台,面向网页开发者提供的基于微信内的网页开发工具包。
借助这个工具包,开发这可以快速方便调用微信上的一些功能,例如拍照,选图,扫一扫等……
前端参考:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#1
后端参考:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62
前端要想使用 JS-SDK,第一步要先验签,验签因为需要用到 appsecret,为了安全要放在服务器上去计算签名,通过接口返回给到前端。

验签步骤
/*** 获取JS调用凭证刷新Ticket*/public String getTicket(String appId, String appSecret) {Long defaultExpire = 600L;String accessToken = this.getAccessToken(appId, appSecret);String ticketKey = "wx:ticket" ;String val = redisUtil.get(ticketKey);Long expire = redisUtil.getExpire(ticketKey);if (Objects.nonNull(val) && expire > defaultExpire) {return val;}return this.refreshTicket(ticketKey, accessToken);}/*** 刷新Ticket*/public String refreshTicket(String ticketKey, String accessToken) {String ticketUri = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi";try {String url = MessageFormat.format(ticketUri, accessToken);JSONObject ticket = RequestUtil.get(url);WeChatTicket weChatTicket = JSON.to(WeChatTicket.class, ticket);if (Objects.nonNull(weChatTicket) && Objects.equals(weChatTicket.getErrcode(), 0)) {redisUtil.set(ticketKey, weChatTicket.getTicket(), weChatTicket.getExpiresIn());return weChatTicket.getTicket();}} catch (Exception e) {e.printStackTrace();}return null;}@Datapublic class WeChatTicket {@ApiModelProperty(name = "ticket", value = "js凭证")private String ticket;@ApiModelProperty(name = "expires_in", value = "过期时间")@JsonProperty("expires_in")private Integer expiresIn;@ApiModelProperty(name = "errcode", value = "状态码")private int errcode;}
//最终获取到的签名方法public JsSignVo wxSignature(String url) {if (StringUtils.isEmpty(url)) {return Result.error("url不能为空");}String ticket = weChatUtil.getTicket(appId, appSecret);if (StringUtils.isNotBlank(ticket)) {try {//前端传的地址编码了,所以需要先解码url = URLDecoder.decode(url, "UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}String nonceStr = UUID.randomUUID().toString();String timestamp = String.valueOf(System.currentTimeMillis() / 1000);String content = MessageFormat.format("jsapi_ticket={1}&noncestr={0}×tamp={2}&url={3}", nonceStr, ticket, timestamp, url);String signature = sha1(content);if (StringUtils.isNotBlank(signature)) {JsSignVo jsSignVo = new JsSignVo();jsSignVo.setNonceStr(nonceStr);jsSignVo.setTimestamp(timestamp);jsSignVo.setSignature(signature);return jsSignVo;}}return null;}@Datapublic class JsSignVo {@ApiModelProperty(name = "nonceStr", value = "随机字符串")private String nonceStr;@ApiModelProperty(name = "timestamp", value = "时间戳")private String timestamp;@ApiModelProperty(name = "signature", value = "签名")private String signature;}public static String sha1(String str) {try {MessageDigest md = MessageDigest.getInstance("SHA-1");md.update(str.getBytes());byte[] digest = md.digest();StringBuilder sb = new StringBuilder();for (byte b : digest) {sb.append(String.format("%02x", b));}return sb.toString();} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);}}
签名后可以通过官方提供的工具去生成比对,https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
签名比对一致后,前端就可以正常去使用 JS-SDK 工具包中的功能。
