最近公司的后台管理系统,决定做成可以微信扫码登录,然后各种站内信消息可通过微信下发。
于是开启了下面的微信登录集成路的一波三折。
首先你得有个认证通过的公众号(服务号),认证费300大洋,还得有个微信开放平台的账号,也要认证,同样300大洋。
思路是这样的:用户在登录界面扫码登录,然后服务器收到微信服务器的回调(会带上参数:code,state),这时服务器那上参数code,加上开放平台的appid,secret去微信服务器获取用户unionid(这玩意同一开放平台下的公众号,小程序针对同一用户都是一样的,所以根据这个来做用户登录),然后根据unionid获取用户,如果获取到了直接登录,若是获取不到,说明用户还没绑定微信,则提示用户先用密码登录,然后绑定微信,这样下次就可以扫码登录了。
接下来是用户绑定微信。因为后面要做基于微信的消息下发,所以需要基于公众号的消息来往,如果服务器可以直接给用户下发消息,那么有个前提就是用户必须得先关注该公众号了才可以。
第一步:显示绑定微信的二维码给用户扫。代码如下:
前台通过此接口获取到二维码内容信息(就是一个连接地址),将此内容生成个二维码显示出来给用户扫描。
用户扫码后,微信服务器会将地址跳转到我们设定好的回调地址上,并带上参数,接收回调的地址如下:
@GetMapping(value = "getOpenIDReturn",produces = "text/html")
public ModelAndView getOpenIDReturn(String code, String header) throws Exception {
System.out.println("header:"+header);
JWTInfo info=null;
try {
String headerInfo = StringHelper.AESDncode(header);
if(!"null".equals(headerInfo)) {
info= JSON.parseObject(headerInfo, JWTInfo.class);
}
}catch (Exception e){
e.printStackTrace();
error("鉴权异常");
}
Map<String,String> paras=new HashMap<>();
paras.put("appid", appid);
paras.put("secret", appSecret);
paras.put("code", code);
paras.put("grant_type", "authorization_code");
String url = "https://api.weixin.qq.com/sns/oauth2/access_token";
String wx_response = HttpUtil.sendPost(url, paras);
System.out.println(wx_response);
JSONObject json_req = JSON.parseObject(wx_response);
String access_token=redisCacheService.getStringValue(wx_token_cache);
if(StringUtils.isEmpty(access_token)) {
wx_response = HttpUtil.sendGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + appSecret);
System.out.println(wx_response);
JSONObject token_obj = JSON.parseObject(wx_response);
access_token=token_obj.getString("access_token");
redisCacheService.setStringValue(wx_token_cache,access_token , token_obj.getLongValue("expires_in"));
}
wx_response = HttpUtil.sendGet("https://api.weixin.qq.com/cgi-bin/user/info?access_token="+access_token+"&openid="+json_req.getString("openid")+"&lang=zh_CN");
System.out.println(wx_response);
JSONObject result=JSON.parseObject(wx_response);
if(result.getInteger("subscribe")==0){
String wx_image="http://og-image.oss-cn-shenzhen.aliyuncs.com/system/ougongguojiruanzhuang.jpg";
if(!environmentService.getIsProd()){
wx_image="http://og-image.oss-cn-shenzhen.aliyuncs.com/system/raunzhuangdaojia.jpg";
}
ModelAndView modelAndView=new ModelAndView("follow_wx");
modelAndView.addObject("wx_image",wx_image);
return modelAndView;
}else {
service.updateWeiXin(info.getId(), json_req.getString("openid"), result.getString("unionid"), result.getString("nickname"));
System.out.println(wx_response);
TopicMessage topicMessage = new TopicMessage();
topicMessage.setSockMessageType(TopicMessageType.EVENT);
List<String> receiver = new ArrayList<>();
receiver.add(String.valueOf(info.getId()));
topicMessage.setReceiverList(receiver);
JSONObject messageContent = new JSONObject();
messageContent.put("type", "bind_wx");
messageContent.put("status", true);
messageContent.put("wx_openid", json_req.getString("openid"));
messageContent.put("wx_name", result.getString("nickname"));
topicMessage.setContent(messageContent);
Message message = new Message(MessageType.WEB_MESSAGE);
message.setData(topicMessage);
messageService.sendMsg(message);
return new ModelAndView("bind_wx_success");
}
}
其中最关键的部分为:通过https://api.weixin.qq.com/cgi-bin/user/info获取用户信息时所使用的access_token不可以使用第一步获取openid时拿到的access_token,必须从https://api.weixin.qq.com/cgi-bin/token这个接口获取。本人就在这里栽了半天才爬出来,一直给你报:"errcode":40001,"errmsg":"invalid credential, access_token is invalid or not latest hint
后来从https://api.weixin.qq.com/cgi-bin/token时遇到个小错误:"errcode":40164,"errmsg":"invalid ip 132.XXX.5.XXX, not in whitelist hint,字面意思是发送请求的主机IP不在白名单里,去公众号里配置下即可:
设置完成后,流程完美走通!
特记录之,共勉!