一、需要有一个公众号(可以使用测试号);
申请测试号:
申请测试号网址:点击
或者进入公众号平台,路径:开发>开发者工具
二、配置测试号信息
1、接口配置验证
package com.example.wx.controller;
import javax.servlet.http.HttpServletRequest;
import com.example.wx.utils.SignUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.http.HttpServletResponse;
/**
* @Description: 微信校验服务器资源
* @author:chaoyapeng
* @time:2020/9/16
* @Version V1.0
*/
@RestController
@Slf4j
public class AgentWeixinReplyController {
@RequestMapping(value = "/wx/reply")
public void get(HttpServletRequest request, HttpServletResponse response) throws Exception {
Enumeration pNames = request.getParameterNames();
while (pNames.hasMoreElements()) {
String name = (String) pNames.nextElement();
String value = request.getParameter(name);
// out.print(name + "=" + value);
String log = "name =" + name + " value =" + value;
}
String signature = request.getParameter("signature");/// 微信加密签名
String timestamp = request.getParameter("timestamp");/// 时间戳
String nonce = request.getParameter("nonce"); /// 随机数
String echostr = request.getParameter("echostr"); // 随机字符串
PrintWriter out = response.getWriter();
if (SignUtil.checkSignature(signature, timestamp, nonce)) {
log.info("微信校验成功!");
out.print(echostr);
}
out.close();
out = null;
}
}
package com.example.wx.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
/**
* @Description: 请求校验工具类
* @author:chaoyapeng
* @time:2020/9/16
* @Version V1.0
*/
public class SignUtil {
// 与接口配置信息中的Token要一致
private static String token = "token_core";
/**
* 验证签名
*
* @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);
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;
}
}
三、进入公众号开发者中心页配置授权回调域名
具体位置:接口权限-网页服务-网页账号-网页授权获取用户基本信息-修改
四:授权步骤:
1、引导用户进入授权页面同意授权,获取code
2、通过code换取网页授权access_token(与基础支持中的access_token不同)
3、通过网页授权access_token和openid获取用户基本信息
具体请参考: 微信网页授权开发文档
代码实现
AuthUtil工具类:
package com.example.wx.utils;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
/**
* @Description: 微信授权工具类
* @author:chaoyapeng
* @time:2020/9/17
* @Version V1.0
*/
public class AuthUtil {
public static final String APPID = "wx15df95c5963eadde";
public static final String APPSECRET = "16a6df30044bf275583c460724bced6b";
//回调地址
public static final String backUrl="http://h5.free.qydev.com/callBack";
public static JSONObject doGetJson(String url) throws IOException {
JSONObject jsonObject = null;
//首先初始化HttpClient对象
DefaultHttpClient client = new DefaultHttpClient();
//通过get方式进行提交
HttpGet httpGet = new HttpGet(url);
//通过HTTPclient的execute方法进行发送请求
HttpResponse response = client.execute(httpGet);
//从response里面拿自己想要的结果
HttpEntity entity = response.getEntity();
if(entity != null){
String result = EntityUtils.toString(entity,"UTF-8");
jsonObject = jsonObject.parseObject(result);
}
//把链接释放掉
httpGet.releaseConnection();
return jsonObject;
}
}
controller:
package com.example.wx.controller;
import com.alibaba.fastjson.JSONObject;
import com.example.wx.domain.User;
import com.example.wx.utils.AuthUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
/**
* @Description: 微信授权
* @author:chaoyapeng
* @time:2020/9/17
* @Version V1.0
*/
@Controller
@Slf4j
public class WxController {
/**
* 引导用户进入授权页面同意授权,获取code
* @param request
* @param response
* @throws IOException
*/
@RequestMapping(value="wxlogin")
public void wx(HttpServletRequest request, HttpServletResponse response) throws IOException {
//第一步:引导用户进入授权页面同意授权,获取code
StringBuilder builder = new StringBuilder("https://open.weixin.qq.com/connect/oauth2/authorize?appid=");
builder.append(AuthUtil.APPID);
builder.append("&redirect_uri=");
builder.append(URLEncoder.encode(AuthUtil.backUrl));//开发文档要求转换
builder.append("&response_type=code");
builder.append("&scope=snsapi_userinfo");
builder.append("&state=STATE#wechat_redirect");
//授权页面地址
//将StringBuilder转换成String
String url = builder.toString();
//重定向到授权页面
response.sendRedirect(url);
}
/**
* 通过第一步获取的code换取网页授权access_token和openid
* @param code
* @param model
* @return
* @throws IOException
*/
@RequestMapping(value="callBack")
public String wxcallback(@RequestParam("code") String code, Model model)throws IOException {
log.info("code:{}",code);
//获取code后,请求以下链接获取access_token
StringBuilder builder = new StringBuilder("https://api.weixin.qq.com/sns/oauth2/access_token?appid=");
builder.append(AuthUtil.APPID);
builder.append("&secret=");
builder.append(AuthUtil.APPSECRET);
builder.append("&code=");
builder.append(code);
builder.append("&grant_type=authorization_code");
//通过网络请求方法来请求上面这个接口
//将StringBuilder转换成String
String url = builder.toString();
JSONObject jsonObject = AuthUtil.doGetJson(url);
log.info("jsonObject:{}",jsonObject);
//从返回的JSON数据中取出access_token和openid,拉取用户信息时用
String token = jsonObject.getString("access_token");
String openid = jsonObject.getString("openid");
// 第三步:刷新access_token(如果需要)
// 第四步:拉取用户信息(需scope为 snsapi_userinfo)
StringBuilder builder1 = new StringBuilder("https://api.weixin.qq.com/sns/userinfo?access_token=");
builder1.append(token);
builder1.append("&openid=");
builder1.append(openid);
builder1.append("&lang=zh_CN");
//通过网络请求方法来请求上面这个接口
//将StringBuilder转换成String
String infoUrl = builder1.toString();
JSONObject userInfo = AuthUtil.doGetJson(infoUrl);
log.info("userInfo:{}",userInfo);
model.addAttribute("info",userInfo);
return "wx/index";
}
}
前端显示页面是使用thymeleaf模板
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>授权成功</title>
</head>
<body>
<div><img width="100" th:src="${info.headimgurl }"></div>
<div>昵称:<font th:text="${info.nickname}"></font></div>
<div>地址:<font th:text="${info.country}"></font></div>
<div>openId:<font th:text="${info.openid}"></font></div>
</body>
</html>
五、自定义菜单
1、填写appid、appsecret获取access_token
2、自定义菜单
body内容:
{
"button": [
{
"name": "授权",
"sub_button": [
{
"type": "view",
"name": "获取授权",
"url": "http://h5.free.qydev.com/wxlogin"
}
]
}
]
}
菜单效果图:
六、效果