前两个星期在公司中的项目加上了微信登录、绑定的功能,在这里做个记录!
一、开发前知识
1、微信开放平台与微信公众平台的区别
1.1 微信公众平台:
① 地址:https://mp.weixin.qq.com/cgi-bin/loginpage?t=wxm2-login&lang=zh_cn
② 微信公众平台面向的是普通的用户,比如自媒体和媒体,企业官方微信公众账号运营人员使用,当然你所在的团队或者公司有实力去开发一些内容,也可以调用公众平台里面的接口,比如自定义菜单,自动回复,查询功能。
1.2 微信开放平台:
① 地址:
微信开放平台:面向的是开发者和第三方独立软件开发商。开放平台的文档似乎包含了微信开放平台文档里面的接口。
2、微信公众平台目前只支持80端口,且项目上传到服务器上面不容易debug啊?
解决方法:ngrok 工具,可以根据本地项目映射成外网可以访问的地址、端口,默认映射为80端口。
官网:
存在问题: 每次重启,域名会变化,都需要项目中、微信公众平台配置,付费可以固定域名。。。
使用方法: ① 注册后获得一个授权码,下载 ngrok
② 》cmd 进入 ngrok 目录
》ngrok authtoken 授权码
》ngrok http 8080
③看到这个页面,ngrok就为你分配了临时访问通道成功了^^
二、配置
(每个微信号可以申请成为开发者测试账号进行微信功能开发的。)
1、在公众平台中进行配置:
地址:
①:配置“接口配置信息” (token 在项目中我是配置为"handsomeking",没错,我就是king ^^)
url 改为自己映射的域名
② 配置“功能服务” 的 “网页帐号”。注意,是域名
好了,可以愉快的coding 了!!!
三、可以开发啦
1、上面的 “接口配置信息” 配置得 wechat/ownercheck 方法是验证 这个url 为我自己的,handsomeking 就是这个方法中的一个参数。微信这个小朋友会用get方法带上4个参数给我服务器: signature(签名)、timestamp(时间戳)、nonce(随机数)、echostr(随机字符串),再加上咱们项目中自己配置的 token ,通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败:(talk is cheap, show me the code *&)
/** * 微信消息接收和token验证 * @param model * @param request * @param response * @throws ioexception */ @requestmapping("/ownercheck") public void ownercheck(model model, httpservletrequest request,httpservletresponse response) throws ioexception { system.out.println(111); boolean isget = request.getmethod().tolowercase().equals("get"); printwriter print; if (isget) { // 微信加密签名 string signature = request.getparameter("signature"); // 时间戳 string timestamp = request.getparameter("timestamp"); // 随机数 string nonce = request.getparameter("nonce"); // 随机字符串 string echostr = request.getparameter("echostr"); // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败 if (signature != null && checkoututil.checksignature(signature, timestamp, nonce)) { try { print = response.getwriter(); print.write(echostr); print.flush(); } catch (ioexception e) { e.printstacktrace(); } } } }
import java.security.messagedigest; import java.security.nosuchalgorithmexception; public class checkoututil { // 与接口配置信息中的token要一致 private static string token = "handsomeking"; /** * 验证签名 * * @param signature * @param timestamp * @param nonce * @return */ public static boolean checksignature(string signature, string timestamp, string nonce) { string[] arr = new string[] { token, timestamp, nonce }; // 将token、timestamp、nonce三个参数进行字典序排序 // arrays.sort(arr); sort(arr); stringbuilder content = new stringbuilder(); for (int i = 0; i < arr.length; i++) { content.append(arr[i]); } messagedigest md = null; string tmpstr = null; try { md = messagedigest.getinstance("sha-1"); // 将三个参数字符串拼接成一个字符串进行sha1加密 byte[] digest = md.digest(content.tostring().getbytes()); tmpstr = bytetostr(digest); } catch (nosuchalgorithmexception e) { e.printstacktrace(); } content = null; // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信 return tmpstr != null ? tmpstr.equals(signature.touppercase()) : false; } /** * 将字节数组转换为十六进制字符串 * * @param bytearray * @return */ private static string bytetostr(byte[] bytearray) { string strdigest = ""; for (int i = 0; i < bytearray.length; i++) { strdigest += bytetohexstr(bytearray[i]); } return strdigest; } /** * 将字节转换为十六进制字符串 * * @param mbyte * @return */ private static string bytetohexstr(byte mbyte) { char[] digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; char[] temparr = new char[2]; temparr[0] = digit[(mbyte >>> 4) & 0x0f]; temparr[1] = digit[mbyte & 0x0f]; string s = new string(temparr); return s; } public static void sort(string a[]) { for (int i = 0; i < a.length - 1; i++) { for (int j = i + 1; j < a.length; j++) { if (a[j].compareto(a[i]) < 0) { string temp = a[i]; a[i] = a[j]; a[j] = temp; } } } } }
2、用户用户同意授权,获取微信服务器传过来的俩参数: code、state。其中:
appid: 微信开发者测试账号
redirect_uri: 同意授权后跳转的 url
/** * 第一步:用户同意授权,获取code(引导关注者打开如下页面:) * 获取 code、state */ public static string getstarturltogetcode() { string takenurl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=redirect_uri&response_type=code&scope=scope&state=state#wechat_redirect"; takenurl= takenurl.replace("appid", param.appid); takenurl= takenurl.replace("redirect_uri", url.encode(param.redirect_uri)); //fixme : snsapi_userinfo takenurl= takenurl.replace("scope", "snsapi_userinfo"); system.out.println(takenurl); return takenurl; }
3、获取微信用户的 access_token、openid
appid:微信开发者测试账号
secret:微信开发者测试账号密码
code::上一步的 code
/** * 获取access_token、openid * 第二步:通过code获取access_token * @param code url = "https://api.weixin.qq.com/sns/oauth2/access_token * ?appid=appid * &secret=secret * &code=code * &grant_type=authorization_code" * */ public static oauthinfo getaccess_token(string code){ string authurl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=appid&secret=secret&code=code&grant_type=authorization_code "; authurl= authurl.replace("appid", param.appid); authurl = authurl.replace("secret", param.secret); authurl = authurl.replace("code", code); string jsonstring = httprequestutil.sendpost(authurl,""); system.out.println("jsonstring: " + jsonstring); oauthinfo auth = null; try { auth = (oauthinfo) jacksonutil.parsejsontoobject(oauthinfo.class, jsonstring); } catch (exception e) { e.printstacktrace(); } return auth; }
4、在数据库中查询 openid
我是定义了一个对象 oauthinfo,包括 openid(用户的标识)属性。。。
查询时库中存在就直接登录啦,不存在就先去登录页,将登录账号同 openid 绑定。
/** * 微信引导页进入的方法 * @return */ @requestmapping("/loginbyweixin") public string loginbyweixin(httpservletrequest request, map<string, object> map) { // 微信接口自带 2 个参数 string code = request.getparameter("code"); string state = request.getparameter("state"); system.out.println("code = " + code + ", state = " + state); if(code != null && !"".equals(code)) { // 授权成功, 微信获取用户openid oauthinfo authinfo = weixinutil.getaccess_token(code); string openid = authinfo.getopenid(); string access_token = authinfo.getaccess_token(); if(access_token == null) { // code 使用过 异常 system.out.println("code 使用过 异常....."); return "redirect:" + weixinutil.getstarturltogetcode(); } // 数据库中查询微信号是否绑定平台账号 sysuser sysuser = weixinservice.getuserbyweixinid(openid); if(sysuser == null) { string randomstr = stringutil.getrandomstring(50); request.getsession().setattribute(openid, randomstr); // 尚未绑定账号 system.out.println("尚未绑定账号....."); return "redirect:/index.jsp?openid=" + openid + "&state=" + randomstr; } usercontroller.dosomeloginworktohomepage(sysuser.getmcid(), map); // 登录成功 return "homepage"; } // 未授权 return "redirect:" + weixinutil.getstarturltogetcode(); }
四、踩过的坑
1、access_token 与普通 access_token。这尼玛是啥关系?
答:access_token: 登录授权会得到一个 access_token, 这个是用于标识登录用户(没有使用次数限制),绑定流程中用的都是 登录 access_token。
普通 access_token: 调用其它微信应用接口时需要带上的 access_token,普通 access_token时效为 2h, 每个应用每天调用次数<= 2000次。(实际开发时必须加以处理。。我采用的是 quartz 调度^^)
2、uuid、openid。我该绑定uuid?不不不,openid?不不,到底绑哪个?
答:uuid:微信号绑定后才有的标识,对于任何应用该微信账号的 uuid 均相同。同一个微信账号不同的应用 uuid 相同。
openid:微信号对于每个应用均有一个不变的 openid,同一个微信账号不同的应用 openid 不同。
五、参考的链接!感谢!!
文中也许会存在我理解上的错误,望各位不吝赐教,小弟定会加以改正。
更多精彩内容请点击《java微信开发教程汇总》欢迎大家学习阅读。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。
如对本文有疑问, 点击进行留言回复!!
Algebra:Chapter 0 - 预备知识: 集合论和categories
springboot + vue上传图片在服务器并实现在线预览
请谨慎使用增强for循环,刚接触Java值得一看(手动狗头)
【Nginx】还不会使用Nginx解决跨域问题?肝这一篇就够了!!
网友评论