700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 微信公众号中获取openid与调用扫一扫功能

微信公众号中获取openid与调用扫一扫功能

时间:2021-01-01 09:20:21

相关推荐

微信公众号中获取openid与调用扫一扫功能

微信公众号中实现获取openid与调用扫一扫功能

环境:微信公众号,vue,脚手架,vuex(可以不用)。

问题:history模式下ios端要同时获取openid与调用微信扫一扫功能非常麻烦。建议将模式修改成hash。

需要提前处理的问题:1,在微信公众平台进行服务器配置,2,配置JS接口安全域名和网页授权域名,3,配置IP白名单。

关键词:appid,appsecret,code,redirect_uri,openid,扫一扫。

使用hash路由模式的情况下,这种方式在微信公众号里边要同时获取微信openid和调用扫一扫功能还是比较简单的。下面是我解决问题的思路。

一,首先是获取用户的openid

第一步:需要在微信公众号首页根据微信提供的请求url获取当前用户的code信息。大概实现逻辑就是,先通过微信提供的url进行信息配置。其中redirect_uri是向微信发起请求之后需要跳转的地址(最好设为当前页),oppid微信公众平台提供给你的oppid。redirect_uri本案例配置的是首页地址,也就是进入首页之后根据location.href获取首页的url地址。然后进行如下配置(特别注意的是url需要encodeURIComponent处理)

var redirect_uri= location.href;

https://open./connect/oauth2/authorize?appid=wx77845299abcf81f1&redirect_uri=' encodeURIComponent(redirect_uri) + '&response_type=code&scope=snsapi_base&state=0#wechat_redirect。

第二步:通过上面的配置地址向微信发起请求(此请求必须是要在微信客户端发起,否则会提示你需要在微信客户端打此开连接),请求发出后微信服务器会根据当前用户信息生成一个code的参数附加在你设置的跳转地址里边。我设置的跳转页就是首页,所以会刷新首页,然后就可以在刷新后的页面地址里边拿到code信息。

第三步:拿到code信息后便可以向后端发起获取用户openid的请求了(其中oppId,appsecret就是你微信公众平台给你的):

后台代码如下 :

/*** 根据code 获取用户openID*/public BaseResp getUserOpenId(String code) {BaseResp resp = new BaseResp();String requestUrl = "https://api./sns/oauth2/access_token";;String params = "?appid=" + this.oppId + "&secret=" + this.appsecret + "&code=" + code+ "&grant_type=authorization_code";String result = this.httpGet(requestUrl + params);log.info("################h5获取当前用户信息:" + JSON.toJSONString(result));String openid = JSONObject.parseObject(result).getString("openid");resp.setCode(MessageEnum.SUCCESS.toString());resp.setMsg(openid);// 当前用户openidreturn resp;}

前端代码如下(可以直接copy使用)

methods: {getOpenId: function() {var this_ = this;//第一步从地址中获取codevar access_code = this_.getQueryString('code');if (access_code == null) {var fromurl = location.href; // 获取授权code的回调地址,获取到code,直接返回到当前页var url = 'https://open./connect/oauth2/authorize?appid=appid&redirect_uri=' +encodeURIComponent(fromurl) +'&response_type=code&scope=snsapi_base&state=0#wechat_redirect';location.href = url;} else {let api = this_.requestUrl+"/wx/open/getOpenId?code=" + access_code;this.$axios.get(api).then((response) => {this_.openId = response.data.msg;//this.$mit('updateOpenId',response.data.msg) }).catch(function(error) {alert(error);});}},getQueryString: function(name) {var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");var r = location.search.substr(1).match(reg);if (r != null)return unescape(decodeURI(r[2]));return null;},},created() {let openId=this.$store.state.globalOpenId;if(openId==null){this.getOpenId();}}

这样就完成在微信公众号里边获取用户的openid了。

二,实现调用微信扫一扫

关键字:jsapi_ticket

逻辑:微信公众号在调用扫一扫功能之前需要对当前页授权才行。所以后端根据当前页的url和后端获取其他一系列的参数生成一个signature的签名,用于做前端授权验证,只要验证通过了就可以调用扫一扫功能了(官方文档说明)。

第一步:首先获取当前页的url,将url使用encodeURIComponent处理。

第二步:根据当前页的url从服务器端异步获取授权页配置信息(后端实现需要通过微信公众号的openid与secret获取access_token,再根据access_token获取jsApi-ticket票据;然后再根据票据,noncestr,timestamp,和前端传入的url进行sha-1加密处理得到授权页需要的signature验证信息;最后将微信公众号oppid和生成的timestamp,nonceStr,signature返回给前端;前端获取到这些信息后做如下图配置就可以。。。这一步稍微有一点繁琐,但是都是后端实现,前端不用管,在附录一中我会将后端实现代码粘出来)。

第三步:配置需要调用的控件,下面我配置的是scanQRCode扫一扫。

created: function() {//alert(this.$route.query.openId)this.openId = this.$store.state.globalOpenId;//this.$route.query.openId;let url=encodeURIComponent(location.href.split('#')[0]);this.$axios({method: 'post',url: this.requestUrl + '/wx/open/getSign?url=' + url,}).then(function(response) {var data = response.data;wx.config({debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: data.appId, // 必填,公众号的唯一标识timestamp: data.timestamp, // 必填,生成签名的时间戳nonceStr: data.nonceStr, // 必填,生成签名的随机串signature: data.signature, // 必填,签名,见附录1jsApiList: ['scanQRCode']});});}

第四步:如果上一步验证成功,那么接下来就直接调用下面定义的函数就可以打开扫一扫了。

openScan: function() { //扫一扫var _this = thiswx.scanQRCode({needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,scanType: ["qrCode"], // 可以指定扫二维码还是一维码,默认二者都有success: function(res) {var msg = res.resultStr;}});},

附录一

需要用到的url

public static final String access_token_url = "https://api./sns/oauth2/access_token";public static final String token_url = "https://api./cgi-bin/token";public static final String getticket_url = "https://api./cgi-bin/ticket/getticket";public static final String template_url = "https://api./cgi-bin/message/template/send";

获取签名

/*** 获取sign签名* * @return*/public Map sign(HttpServletRequest request, HttpServletResponse response) {// HttpServletRequest request = ServletActionContext.getRequest();Map ret = new HashMap();String url = request.getParameter("url");String jsapi_ticket = getJsapiTicket(request, response);String nonce_str = create_nonce_str();String timestamp = create_timestamp();String string1;String signature = "";int length = url.indexOf("#");String uri = url;if (length > 0) {uri = url.substring(0, length);// 当前网页的URL,不包含#及其后面部分}// 注意顺序string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str + "&timestamp=" + timestamp + "&url=" + url;log.info("string1=" + string1);try {MessageDigest crypt = MessageDigest.getInstance("SHA-1");crypt.reset();crypt.update(string1.getBytes("UTF-8"));signature = byteToHex(crypt.digest());} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();}ret.put("appId", this.oppId);ret.put("url", uri);ret.put("jsapi_ticket", jsapi_ticket);ret.put("nonceStr", nonce_str);ret.put("timestamp", timestamp);ret.put("signature", signature);System.out.println(signature);// this.setJsonString(JSON.toJSONString(ret));log.info("获取sign结果:" + JSON.toJSONString(ret));return ret;}private static String byteToHex(final byte[] hash) {Formatter formatter = new Formatter();for (byte b : hash) {formatter.format("%02x", b);}String result = formatter.toString();formatter.close();return result;}private static String create_nonce_str() {return UUID.randomUUID().toString();}private static String create_timestamp() {return Long.toString(System.currentTimeMillis() / 1000);}/*** 发送get请求* * @param url* 路径* @return*/public static String httpGet(String url) {String strResult = null;try {DefaultHttpClient client = new DefaultHttpClient();HttpGet request = new HttpGet(url);HttpResponse response = client.execute(request);if (response.getStatusLine().getStatusCode() == org.apache.http.HttpStatus.SC_OK) {strResult = EntityUtils.toString(response.getEntity());} else {log.info("get请求提交失败:" + url);}} catch (IOException e) {log.info("请求异常:" + e.getMessage());}return strResult;}

获取access_token

public String getWxToken() {//每次获取新最新token// 当过期时间超过两小时,则重新获取新的access_tokenString requestUrl = WxOpenBusi.token_url;String params = "?grant_type=client_credential&appid=" + this.oppId + "&secret=" + this.appsecret + "";String result = WxOpenBusi.httpGet(requestUrl + params);log.info("################获取微信token结果:" + JSON.toJSONString(result));String accessToken_t = JSONObject.parseObject(result).getString("access_token");return accessToken_t;}

获取临时票据

/*** 得到jsApi-ticket* * @return*/@SuppressWarnings({ "static-access", "unused" })private String getJsapiTicket(HttpServletRequest request, HttpServletResponse response) {// String code = request.getParameter("code");// String requestUrl = "https://api./cgi-bin/token?";// String params = "grant_type=client_credential&appid=" + oppId +// "&secret=" + appsecret + "";// String result = this.httpGet(requestUrl + params);// log.info("################平台获取微信调用接口token结果:" +// JSON.toJSONString(result));String accessToken = this.getWxToken();String jsapi_ticket = WxOpenBusi.jsapi_ticket;Long curTime = System.currentTimeMillis();if ((WxOpenBusi.ticket_expiration_time + 7140000) < curTime) {WxOpenBusi.ticket_expiration_time = System.currentTimeMillis();String requestUrl = WxOpenBusi.getticket_url;String params = "?access_token=" + accessToken + "&type=jsapi";String result = this.httpGet(requestUrl + params);log.info("################平台调微信jsApi-ticket接口获取ticket结果:" + JSON.toJSONString(result));jsapi_ticket = JSONObject.parseObject(result).getString("ticket");WxOpenBusi.jsapi_ticket = jsapi_ticket;}return jsapi_ticket;}

响应给前端的对象

public class BaseResp implements Serializable {private static final long serialVersionUID = -901432767858826220L;@Setter@Getterprivate String code;@Setter@Getterprivate String msg;@Setter@Getterprivate String status;//预留属性@Setter@Getterprivate Object data;

到这里实现微信公众号中获取用户oppid和实现调用扫一扫功能的全部代码和实现逻辑就完了。谢谢大家阅读!一年多没有写博客了,若有不足支持还请多多提点。

当然,签名都是基于hash模式下实现的。如果要在history模式下实现的话ios兼容性就很难控制了。我直接最初使用的就是history模式,结果花了一天多去处理ios的兼容问题,结果也很不如意。问题就出在在实现调用扫一扫功能的时候向后台传递的url的问题上,因为这会涉及到多个页面跳转时ios系统对当前页url不像安卓一样只需要用location.href就可以。而是它存在依赖关系。就比如:现在有两个页面A,B。A是首页,B是通过A跳转去的页面。那么这个时候你想要在B页面中实现调用扫一扫功能,你需要传的地址应该是A的地址,而不是当前页B的地址,具体解决方案可以参考微信 jssdk 签名错误 invalid signature。

然而,真正的问题却不是A跳转到B页面能不能实现微信扫一扫的问题,而是在一般情况下我们都会在微信首页中去先获取用户的oppid,然后把他存储起来。

问题就出在我们在获取用户oppid的时候是需要先去获取code参数的,而获取code这个参数就需要刷新当前的页面,就如我最上面说的,会根据微信提供获取code的url配置跳转的地址,而这个跳转地址基本上都是当前页页就是首页,这样就会存在首页需要刷新才可以获取得到code的信息。问题就出在刷新之后,首页A在跳转到B页面去后端获取sign配置参数的时候配置的当前页的url就非常难以控制。。。

如果你不相信你去验证之后就会发现,你传最初进入首页的这个首页地址是不对的,然后你尝试传递首页刷新之后的地址(这时的地址会带有code,state等参数)的时候也不对,最后你只能再尝试一下传递B页面的当前页地址,最后你会发现都不行。。。。这就就很痛苦了吧,它不像安卓那样很简单,你那个页面需要调扫一扫功能你就传那个页面的url就可以了,但是ios只要有页面刷新或者页面跳转就不行。所以最后未来解决这个问题我之后把vuecli的路由模式修改为hash了。

这是我踩的坑,希望大家看到后有所帮助吧。如果大家有什么好的建议希望在评论区留言,我也学习学习,谢谢!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。