admin管理员组文章数量:1530842
碰到这样一个需求,PC端生成公众号二维码,用户用手机微信扫描,如果用户未关注公众号,则关注公众号后自动登录,如果用户已经关注过公众号,则直接登录。
前端Vue,后端Java实现
分2步来完成:
1.生成带参数的临时二维码
https://developers.weixin.qq/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html
2. 公众号后台服务监听扫码事件并获取用户信息
https://developers.weixin.qq/doc/offiaccount/Message_Management/Receiving_event_pushes.html
https://developers.weixin.qq/doc/offiaccount/User_Management/Get_users_basic_information_UnionID.html#UinonId
1.生成带参数的临时二维码
获取临时二维码的接口为微信官方提供的
https://api.weixin.qq/cgi-bin/qrcode/create?access_token=TOKEN,注意为POST方式
@RequestMapping("/getQRCode")
public Map<String,Object> getQRCode(HttpServletRequest request,String code) {
Map<String,Object> map = new HashMap<String,Object>();
String code_url = "https://api.weixin.qq/cgi-bin/qrcode/create?access_token=TOKEN";
try{
//获取公众号的Token,自行实现,我是定任务获取,存到了数据库
PcAccessToken token = accessTokenService.findPcToken("");
code_url = code_url.replace("TOKEN", token.getAccessToken());
String scene_id = (System.currentTimeMillis()+"").substring(0,10);
JSONObject json = new JSONObject();
json.put("expire_seconds", "36000");
json.put("action_name", "QR_SCENE");
JSONObject info = new JSONObject();
JSONObject scen = new JSONObject();
scen.put("scene_id", scene_id);
info.put("scene", scen);
json.put("action_info", info);
String data = HttpUtil.requestPost(code_url, json.toString());
JSONObject resp = JSONObject.fromObject(data);
System.out.println("data=="+data);
map.put("data", resp);
map.put("scene_id", scene_id);
map.put("succ", "1");
} catch(Exception e){
map.put("succ", "0");
e.printStackTrace();
}
return map;
}
请求微信接口返回的数据,url参数即为二维码地址,和scene_id一起返回给前端。
前端vue使用 qrcodejs2组件,将url转为二维码图片,显示在相应位置。请求到二维码后,用sceneId查询扫码登录是否成功。
<div class="" id="qrcode" ref="qrcode"></div>
import QRCode from 'qrcodejs2'
import loginApi from '@/api/login';
data(){
return{
url: '', //二维码地址
sceneId:'',//二维码带的参数,用来判断是那个用户扫码的
timer: null,//定时器
}
},
created(){
getLoginQRCode();
},
methods:{
async getLoginQRCode(){
this.url = '';
window.clearInterval(this.timer);
const res = await loginApi.getQRCode();
console.log('44res',res)
if(res.data.succ == '1'){
this.url = res.data.data.url;
this.sceneId = res.data.scene_id;
console.log('sceneId',res.data.scene_id);
this.timer = setInterval(this.getUserByScene, 1000);
this.$nextTick(() => {
this.getQrcode(this.url)
})
}
},
//根据 sceneId 轮询查询用户信息,判断用户是否登录成功
async getUserByScene(){
if(!this.sceneId) return;
const res = await loginApi.getUserBySceneId({sceneId: this.sceneId});
console.log('getUser', res);
if(res.data.succ == '1' && res.data.user){
this.user = res.data.user;
window.clearInterval(this.timer);
this.url = '';
this.sceneId = '';
//登录成功,处理登录成功逻辑
this.$Message.success('登录成功')
}
},
getQrcode (text) {
this.$refs.qrcode.innerHTML = '' // 清除
const qrcode = new QRCode('qrcode', {
width: 160,
height: 160,
text: text, // 二维码地址
colorDark: '#000',
colorLight: '#fff'
})
return qrcode
},
}
2.公众号后台服务监听扫码事件并获取用户信息
这块要在微信公众平台配置服务地址信息
开发—基本配置
服务器配置信息提交的时候要验证 TOKEN, 验证通过才能提交。checkToken接口GET请求用来验证TOKEN,
import java.security.MessageDigest;
//...
@RequestMapping(value="/checkToken",method=RequestMethod.GET)
public String checkToken(HttpServletRequest req, HttpServletResponse resp)throws IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
String message = "success";
String signature = req.getParameter("signature");
String timestamp = req.getParameter("timestamp");
String nonce = req.getParameter("nonce");
String echostr = req.getParameter("echostr");
try {
String[] arr = {"sjyx", timestamp, nonce};
Arrays.sort(arr);
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
//sha1Hex 加密
MessageDigest md = null;
String temp = null;
md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(content.toString().getBytes());
temp = byteToStr(digest);
if ((temp.toLowerCase()).equals(signature)){
return echostr;
}
return null;
} catch (Exception e) {
e.printStackTrace();
}
return message;
}
private static String byteToStr(byte[] byteArray){
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}
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;
}
checkToken接口POST请求用来监听扫码事件,并获取用户信息
@RequestMapping(value="/checkToken",method=RequestMethod.POST)
public String responseEvent(HttpServletRequest req, HttpServletResponse resp) {
String message = "success";
try {
//把微信返回的xml信息转义成map
Map<String, String> map = XmlUtil.xmlToMap(req);
System.out.println("微信接收到的消息为:"+map.toString());
String openId = map.get("FromUserName");//消息来源用户标识
String toUserName = map.get("ToUserName");//消息目的用户标识
String msgType = map.get("MsgType");//消息类型(event或者text)
String EventKey = map.get("EventKey");//消息来源用户标识
if(EventKey.contains("_")){ //scene_id首次关注会有前缀,去掉就和生成二维码时带的一致了
EventKey = EventKey.split("_")[1];
}
String scene_Id = EventKey;
String eventType = map.get("Event");//事件类型
if("subscribe".equals(eventType) || "SCAN".equals(eventType) ){ //关注 or 浏览
//获取缓存的最新的公众号 token
PcAccessToken token = accessTokenService.findPcToken("");
String USER_INFO_URL = "https://api.weixin.qq/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
USER_INFO_URL = USER_INFO_URL.replace("ACCESS_TOKEN", token.getAccessToken());
USER_INFO_URL = USER_INFO_URL.replace("OPENID", openId);
String info = HttpUtil.getRequest(USER_INFO_URL);
System.out.println("----user-----"+info);
JSONObject obj = JSONObject.fromObject(info);
String unionid = obj.getString("unionid");
String nickname = obj.getString("nickname");
String headimgurl = obj.getString("headimgurl");
String city = obj.getString("city");
String province = obj.getString("province");
String qr_scene = obj.getString("qr_scene");
//获取到用户信息后处理登录逻辑,比如保存用户信息,用户表scene_id 字段,保存二维码的scend_id,供前端查询用户登录情况。
}
} catch (Exception e) {
e.printStackTrace();
}
return message;
}
xml转Map工具类
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class XmlUtil {
/*
* xml转map
*/
public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException{
HashMap<String, String> map = new HashMap<String,String>();
SAXReader reader = new SAXReader();
InputStream ins = request.getInputStream();
Document doc = reader.read(ins);
Element root = doc.getRootElement();
@SuppressWarnings("unchecked")
List<Element> list = (List<Element>)root.elements();
for(Element e:list){
map.put(e.getName(), e.getText());
}
ins.close();
return map;
}
}
版权声明:本文标题:PC端微信扫码关注公众号并登录 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dongtai/1726185218a1059445.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论