2、准备一个域名服务器资源,因为微信公众号和微信回调都需要域名
(一)准备阶段
1、先看看官方给的文档
根据官方文档,主要流程如下:
(1)引导用户进入授权页面同意授权,获取code
(2)通过code换取网页授权access_token(与基础支持中的access_token不同)
(3)刷新access_token(如果有需要)
(3)通过网页授权access_token和openid获取用户基本信息
2、准备一个域名服务器资源,因为微信公众号和微信回调都需要域名
本人没有域名,为了本地开发方便,使用了一个内网穿刺工具ngrok(免费使用)
自己下载下来,双击ngrok.exe运行,然后输入命令,例如:ngrok http localhost:8087,8087为自己项目设置的端口号
其中 http://7ca0c439f61c.ngrok.io 为此次生成的域名。
注意:每次生成域名不一样如果关闭窗口,域名失效,要重新生成,每次在线的持续时间为8小时,时间过了可关闭窗口再次打开重新生成域名
3、准备一个微信测试公众号
直接用微信扫描登录
该页面往下拉
可以使用自己的微信直接扫描关注即可
页面再往下拉
点击修改,填入上面生成的域名,然后确定
页面往上拉,在页面开始的地方有个输入URL和Token的地方(这一步没有也可以)
token可以随意填写,url为域名下你的项目地址,例如:
http://7ca0c439f61c.ngrok.io/checkToken (使用自己的域名)
前提是你的本地项目和域名生成器都在运行,先别着急点提交,因为项目要提供checkToken方法
(二)代码阶段
1、先给上面提供一个checkToken方法
/**
* 用于给微信验证token
* @param request
* @param response
* @return
* @throws IOException
* */
@RequestMapping("/checkToken")
public String checkToken(HttpServletRequest request,HttpServletResponse response) throws IOException {
// 微信加密签名
String signature = request.getParameter("signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 随机字符串
String echostr = request.getParameter("echostr");
if (SignUtil.checkSignature(signature, timestamp, nonce)) {
System.out.println("校验token成功");
return echostr;
}else{
System.out.println("校验token不成功");
return null;
}
}
上述方法用到的SignUtil工具类
/**
* 验证微信token
*/
public class SignUtil {
private static String token = "45j5IoDekLAT";//填你自己的,和公众号填写要一致
public static boolean checkSignature(String signature, String timestamp, String nonce) {
String[] paramArr = new String[] { token, timestamp, nonce };
Arrays.sort(paramArr);
String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);
String ciphertext = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(content.toString().getBytes());
ciphertext = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return ciphertext != null ? ciphertext.equals(signature.toUpperCase()) : false;
}
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;
}
}
在确保域名生成工具和项目成功运行的前提下,可以点击准备阶段最后一步提交按钮
2、编写微信授权方法和获取用户信息方法
/**
* 公众号微信登录授权
*/
@RequestMapping("/wxLogin")
public void wxLogin(HttpServletResponse response) throws IOException {
//这个url的域名必须在公众号中进行注册验证,这个地址是成功后的回调地址
String backUrl = "http://7ca0c439f61c.ngrok.io/callback";//使用自己的域名
// 第一步:用户同意授权,获取code
//请求地址 snsapi_base snsapi_userinfo
String url = "https://open.weixin.qq.com/connect/oauth2/authorize" +
"?appid=" + HttpClientUtil.APPID +
"&redirect_uri=" + URLEncoder.encode(backUrl,"utf-8") +
"&response_type=code" +
"&scope=snsapi_userinfo" +
"&state=STATE#wechat_redirect";
logger.info("forward重定向地址{" + url + "}");
//必须重定向,否则不能成功
response.sendRedirect(url);
}
/**
* 公众号微信登录授权回调函数
*/
@RequestMapping("/callback")
public UserLoginRes callback(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
UserLoginRes userLoginRes = new UserLoginRes();
try{
WXUserInfoReq weixinUserInfo = new WXUserInfoReq();
/*start 获取微信用户基本信息*/
String code = req.getParameter("code");
//第二步:通过code换取网页授权access_token
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?"
+ "appid=" + HttpClientUtil.APPID
+ "&secret=" + HttpClientUtil.APPSECRET
+ "&code=" + code
+ "&grant_type=authorization_code";
System.out.println(url);
String result = HttpClientUtil.doGet(url);
JSONObject jsonObject = JSON.parseObject(result);
/*
{ "access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
*/
String openid = jsonObject.getString("openid");
String access_token = jsonObject.getString("access_token");
//第三步验证access_token是否失效;
String chickUrl = "https://api.weixin.qq.com/sns/auth?access_token="
+ access_token + "&openid=" + openid;
String resultInfo = HttpClientUtil.doGet(chickUrl);
JSONObject chickuserInfo = JSON.parseObject(resultInfo);
System.out.println(chickuserInfo.toString());
if (!"0".equals(chickuserInfo.getString("errcode"))) {
String refreshInfo1 = HttpClientUtil.doGet(chickUrl);
JSONObject refreshInfo = JSON.parseObject(refreshInfo1);
/*
{ "access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE" }
*/
access_token = refreshInfo.getString("access_token");
}
// 第四步:拉取用户信息
String infoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token
+ "&openid=" + openid
+ "&lang=zh_CN";
JSONObject userInfo = JSON.parseObject(HttpClientUtil.doGet(infoUrl));
/*
{ "openid":" OPENID",
"nickname": NICKNAME,
"sex":"1",
"province":"PROVINCE"
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
"privilege":[ "PRIVILEGE1" "PRIVILEGE2" ],
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
*/
System.out.println(userInfo.getString("openid") + ":" + userInfo.getString("nickname") +":" + userInfo.getString("sex"));
}catch (Exception e){
e.printStackTrace();
userLoginRes.setResult("NO");
userLoginRes.setRtnErrId("ERROR");
userLoginRes.setRtnErrMsg(e.getMessage());
}
return userLoginRes;
}
使用到的HttpClientUtil工具类
public class HttpClientUtil {
//appid、secret为自己公众号平台的appid和secret
public static final String APPID="xxxxxxx";
public static final String APPSECRET ="xxxxxxx";
public static String doGet(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
String resultString = "";
CloseableHttpResponse response = null;
HttpGet httpGet = null;
try {
// 创建uri
URIBuilder builder = new URIBuilder(url);
if (param != null) {
for (String key : param.keySet()) {
builder.addParameter(key, param.get(key));
}
}
URI uri = builder.build();
// 创建http GET请求
httpGet = new HttpGet(uri);
httpGet.setHeader("Host", "api.weixin.qq.com");
httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko");
httpGet.setHeader("Accept", "text/html, application/xhtml+xml, */*");
httpGet.setHeader("Accept-Encoding", "gzip, deflate, br");
httpGet.setHeader("Connection", "keep-alive");
httpGet.setHeader("Accept-Language", "zh-CN");
httpGet.setHeader("Cache-Control", "no-cache");
// 执行请求
response = httpclient.execute(httpGet);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
httpGet.releaseConnection();
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doGet(String url) {
return doGet(url, null);
}
public static String doPost(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建参数列表
if (param != null) {
List<NameValuePair> paramList = new ArrayList<>();
for (String key : param.keySet()) {
paramList.add(new BasicNameValuePair(key, param.get(key)));
}
// 模拟表单
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
httpPost.setEntity(entity);
}
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doPost(String url) {
return doPost(url, null);
}
public static String doPostJson(String url, String json) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建请求内容
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doGetStr(String httpurl) {
HttpURLConnection connection = null;
InputStream is = null;
BufferedReader br = null;
String result = null;// 返回结果字符串
try {
// 创建远程url连接对象
URL url = new URL(httpurl);
// 通过远程url连接对象打开一个连接,强转成httpURLConnection类
connection = (HttpURLConnection) url.openConnection();
// 设置连接方式:get
connection.setRequestMethod("GET");
// 设置连接主机服务器的超时时间:15000毫秒
connection.setConnectTimeout(15000);
// 设置读取远程返回的数据时间:60000毫秒
connection.setReadTimeout(60000);
//设置请求头
connection.setRequestProperty("Host", "api.weixin.qq.com");
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko");
connection.setRequestProperty("Accept", "text/html, application/xhtml+xml, */*");
connection.setRequestProperty("Accept-Encoding", "gzip, deflate, br");
connection.setRequestProperty("Connection", "keep-alive");
connection.setRequestProperty("Accept-Language", "zh-CN");
connection.setRequestProperty("Cache-Control", "no-cache");
// 发送请求
connection.connect();
// 通过connection连接,获取输入流
if (connection.getResponseCode() == 200) {
is = connection.getInputStream();
// 封装输入流is,并指定字符集
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
// 存放数据
StringBuffer sbf = new StringBuffer();
String temp = null;
while ((temp = br.readLine()) != null) {
sbf.append(temp);
sbf.append("\r\n");
}
result = sbf.toString();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (null != br) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
connection.disconnect();// 关闭远程连接
}
return result;
}
}
在微信客户端直接访问 http://7ca0c439f61c.ngrok.io/wxlogin 即可(使用自己的域名)
欢迎提出你的意见