Java实现微信扫码关注公众号登录网站
准备工作:
申请一个微信公众号并登录,需要用到里面的两个功能—基本配置和开发者工具
核心思想:
一:在微信公众号后台的基本配置里配置好服务器配置,如图:
需要注意的是,如果你用本地的开发环境的话,URL不能写127.0.0.1或者localhost,需要做内网穿透处理,意思是这里必须用域名,因为小编我用127.0.0.1一直配置不成功,用了内网穿透就成功了。
Token是自己写,我的是写在工具类里的,工具类是网上随便找的一个,写好Token后这里的Token要跟自己写的保持一致。点击随机生成这个EncodingAESKey就行了,然后点击提交,显示配置成功的话就成功了。不成功的原因就是你要先把服务器运行起来,这样这里才能访问到你的URL才能验证你的Token.
二:进入开发者工具,点击公众平台测试账号,如图:
进入后配置接口配置信息就行了:
这里的URL和Token跟基本配置里你写的一模一样,点击提交,显示成功(如果失败了的话就是服务器没运行,只要基本配置里成功了这里一定成功)
代码controller层:
`package com.zzj.qlogin.controller;
import com.zzj.qlogin.cache.RedisCacheManager;
import com.zzj.qlogin.service.WxService;
import com.zzj.qlogin.utils.CheckoutUtils;
import com.zzj.qlogin.utils.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
@Controller
public class HomeController {
Logger logger = LoggerFactory.getLogger(HomeController.class);
@Resource
private WxService wxService;
@Resource
private RedisCacheManager redisCacheManager;
/**
* 首页
* @return
*/
@GetMapping("/")
public String index(){
return "index";
}
/**
* 登陆页面
* @return
*/
@GetMapping("/login")
public String login(){
return "login";
}
/**
* 用于检测扫码和关注状态
* @return
*/
@PostMapping("/checkLogin")
@ResponseBody
public Object checkLogin(String ticket){
//如果redis中有ticket凭证则说明用户已扫码说明登陆成功
if(redisCacheManager.hasKey(ticket)){
//扫码通过则删除
redisCacheManager.delete(ticket);
return true;
}
return false;
}
/**
* 获取二维码参数
* @return
*/
@GetMapping("/getQrCode")
@ResponseBody
public Object getQrCode(){
return wxService.getQrCode();
}
/**
* 登陆成功跳转
* @return
*/
@GetMapping("/success")
@ResponseBody
public String loginSuccess(){
return "登陆成功";
}
/***
* 微信服务器触发get请求用于检测签名
* @return
*/
@GetMapping("/handleWxCheckSignature")
@ResponseBody
public String handleWxCheckSignature(String signature,String timestamp,String nonce,String echostr){
// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
if (signature != null && CheckoutUtils.checkSignature(signature, timestamp, nonce)) {
return echostr;
}
return "";
}
/**
* 接收微信推送事件
* @param request
* @return
*/
@PostMapping("/handleWxCheckSignature")
@ResponseBody
public String handleWxEvent(HttpServletRequest request){
try {
InputStream inputStream = request.getInputStream();
Map<String, Object> map = XmlUtil.parseXML(inputStream);
String userOpenId = (String) map.get("FromUserName");
String event = (String) map.get("Event");
if("subscribe".equals(event)){
// TODO:获取openid判断用户是否存在,不存在则获取新增用户,自己的业务
//自己生成的二维码不管是关注还是扫码都能取到ticket凭证
String ticket = (String) map.get("Ticket");
redisCacheManager.set(ticket,ticket,10*60);
logger.info("用户关注:{}",userOpenId);
}else if("SCAN".equals(event)){
//自己生成的二维码不管是关注还是扫码都能取到ticket凭证
String ticket = (String) map.get("Ticket");
redisCacheManager.set(ticket,ticket,10*60);
logger.info("用户扫码:{}",userOpenId);
}
logger.info("接收参数:{}",map);
} catch (IOException e) {
e.printStackTrace();
}
return "success";
}
}
`
工具类:
`package com.zzj.qlogin.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class CheckoutUtils {
// 与接口配置信息中的Token要一致
private static String token = "mayipansheng";
/**
* 验证签名
*
* @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;
}
/**
* @param a
*/
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;
}
}
}
}
}
`
注意我的controller层的handleWxCheckSignature地址,是用来接收微信平台发送的四个参数,然后返回echostr用作验证,通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败,如图:
总结:这个demo是小编从网上抄来的,但是运行不起来,我修改了一下就行了,主要修改了这个验证微信服务器的地址和applicatio.yml,需要把端口改成80,因为微信服务器http协议只支持80
避坑:
如果本地redis没密码,在yml里就把密码那一行删除,不然会报错,我的配置如图:
这里的appid和secret需要写你微信公众号后台的。
新手上路,菜鸟起步