基于Springboot的微信公众号接入、通过网页授权机制获取用户信息
2018-04-11 22:31
621 查看
因为基于Springboot,所以有些地方需要用Spring的方式来解决,本文默认你已经搭建好Maven环境,我们将通过花生壳做内网穿透,接入公众号并通过网页授权机制获取用户基本信息
· 获得一个测试号,通过花生壳将内网映射在外· 到微信公众平台(测试号)配置接口信息,接入微信公众号
· 通过网页授权机制获取用户信息
一、花生壳是一套动态域名解析服务客户端软件,方便、稳定,今天用它来做内网穿透
因为微信消息发送流程是从用户到微信服务器,再到你的服务器,接收消息后将响应消息发到微信服务器,其再发给用户。这里将自己的电脑作为一台服务器映射在外,方便测试
1、你需要一个测试号,它具有所有接口的使用权限,登录即可使用:微信公众平台接口测试帐号
2、注册花生壳,做内网穿透:点我
之后进入网页,点击添加映射,进入添加页面:
注意 :微信只接受80端口,所以映射类型选择网站80端口
我本机访问地址为127.0.0.1:80,映射后得到外网访问地qiangqiangchen.55555.io
启动服务器(我用的tomcat),即可访问
至此,你已经获得一个所有人都能访问的地址了
二、到微信公众平台(测试号)配置接口信息,接入微信公众号
如图,这里的URL即我们刚刚映射到外网的地址,Token为随意填写,提交信息后,微信服务器将发送GET请求到你填写的服务器地址URL上,GET请求携带四个参数,我们需要将其中三个参数做字典排序、SHA-1加密,然后拿它与另一个参数作对比,相同则证明该信息来自于微信服务器,即校验通过
具体实现:新建校验类WxPubController
import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class WxPubController { //此处TOKEN即我们刚刚所填的token private String TOKEN = "good"; /** * 接收并校验四个请求参数 * @param signature * @param timestamp * @param nonce * @param echostr * @return echostr */ @RequestMapping(value = "/",method=RequestMethod.GET) public String checkName(@RequestParam(name="signature")String signature, @RequestParam(name="timestamp")String timestamp, @RequestParam(name="nonce")String nonce, @RequestParam(name="echostr")String echostr){ System.out.println("-----------------------开始校验------------------------"); //排序 String sortString = sort(TOKEN, timestamp, nonce); //加密 String myString = sha1(sortString); //校验 if (myString != null && myString != "" && myString.equals(signature)) { System.out.println("签名校验通过"); //如果检验成功原样返回echostr,微信服务器接收到此输出,才会确认检验完成。 return echostr; } else { System.out.println("签名校验失败"); return ""; } } /** * 排序方法 */ public String sort(String token, String timestamp, String nonce) { String[] strArray = {token, timestamp, nonce}; Arrays.sort(strArray); StringBuilder sb = new StringBuilder(); for (String str : strArray) { sb.append(str); } return sb.toString(); } /** * 将字符串进行sha1加密 * * @param str 需要加密的字符串 * @return 加密后的内容 */ public String sha1(String str) { try { MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.update(str.getBytes()); byte messageDigest[] = digest.digest(); // Create Hex String StringBuffer hexString = new StringBuffer(); // 字节数组转换为 十六进制 数 for (int i = 0; i < messageDigest.length; i++) { String shaHex = Integer.toHexString(messageDigest[i] & 0xFF); if (shaHex.length() < 2) { hexString.append(0); } hexString.append(shaHex); } return hexString.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return ""; } }
至此,我们已经接入公众号,接下来就可以实现具体业务了
三、 通过网页授权机制获取用户信息
网页授权机制,开发者文档写的很详细,一共五个步骤:
1 :用户同意授权,获取code 2 :通过code换取网页授权access_token 3 :刷新access_token(如果需要) 4 :拉取用户信息(需scope为 snsapi_userinfo) 5 附:检验授权凭证(access_token)是否有效
在这里,我们只需要三个步骤就可以了,即:
1 :用户同意授权,获取code 2 :通过code换取网页授权access_token 3 :拉取用户信息(需scope为 snsapi_userinfo)
接下来,我们来实现它:
1、用户同意授权,获取code
1.1>>>新建UserInfoUtil,得到一个URL,这个URL是让用户去访问的,当用户进入该URL后,如果用户同意授权,微信服务器收到请求,页面将跳转至 redirect_uri/?code=CODE&state=STATE,也就是你的外网访问网址,携带两个参数,一个为code,一个为state
public class UserInfoUtil { //获取code的请求地址 public static String Get_Code = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=STAT#wechat_redirect"; //替换字符串 public static String getCode(String APPID, String REDIRECT_URI,String SCOPE) { return String.format(Get_Code,APPID,REDIRECT_URI,SCOPE); } public static void main(String[] args) { String REDIRECT_URI = "http://qiangqiangchen.55555.io/vote.do"; String SCOPE = "snsapi_userinfo"; //appId String appId = "wx69b8accef39ebb40"; String getCodeUrl = getCode(appId, REDIRECT_URI, SCOPE); System.out.println("getCodeUrl:"+getCodeUrl); }
运行main函数,得到
getCodeUrl:https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx69b8accef39ebb40&redirect_uri=http://qiangqiangchen.55555.io/vote.do&response_type=code&scope=snsapi_userinfo&state=STAT#wechat_redirect
值得注意的是,我这里的scope=snsapi_userinfo,微信文档说的很明确,它还有另一个可选参数snsapi_base,那么他们有什么区别呢?
区别就是当scope=snsapi_userinfo的时候,弹出询问授权页面,用户同意,才可进一步获取用户基本信息,而后者,不会出现询问页面,但只能获取用户openid(用户的唯一标识)
好了,接下来,我们需要让用户去访问这个URL,那么,该怎么实现呢?
分两步:
首先,需要到自己的微信公众号,到接口权限表里找到网页账号,并修改之,如图:
说明一下,这里的域名即我们通过花生壳映射出去的全域名,比如你的域名是aaaaa.cn,那么aaaaa.cn/bbbb/cccc也是可以弹出权限询问页面的
其次,我们需要引导用户通过getCodeUrl来进入我们的首页,所以,我们要将此URL加到微信菜单上去
这里所说菜单,指的是公众号最下边的那一列———
至于怎么加进去,可以用代码方式,也可以直接设置,但目前测试号没有菜单设置功能,如果需要代码设置,请点击百度这里不做介绍
1.2>>>获取code
这里说明一下:code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
微信服务器收到用户请求,
@Controller public class Ind e9fc exController extends BaseController{ @RequestMapping("/vote.do") public ModelAndView listVote(@RequestParam(name="code",required=false)String code, @RequestParam(name="state")String state) { System.out.println("-----------------------------收到请求,请求数据为:"+code+"-----------------------"+state); //……………………业务代码,此处省略 return new ModelAndView("mypages/index", model); } }
2、通过code换取网页授权access_token
2.1>>>新建UserInfoUtil
public class UserInfoUtil { //获取code的请求地址 public static String Get_Code = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=STAT#wechat_redirect"; //替换字符串 public static String getCode(String APPID, String REDIRECT_URI,String SCOPE) { return String.format(Get_Code,APPID,REDIRECT_URI,SCOPE); } //获取Web_access_tokenhttps的请求地址 public static String Web_access_tokenhttps = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"; //替换字符串 public static String getWebAccess(String APPID, String SECRET,String CODE) { return String.format(Web_access_tokenhttps, APPID, SECRET,CODE); } }
2.2>>>因为需要用https的方式请求微信服务器,我们还需要一个以https方式发送请求的工具类:
package com.util; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.URL; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; public class HttpsUtil { /** * 以https方式发送请求并将请求响应内容以String方式返回 * * @param path 请求路径 * @param method 请求方法 * @param body 请求数据体 * @return 请求响应内容转换成字符串信息 */ public static String httpsRequestToString(String path, String method, String body) { if (path == null || method == null) { return null; } String response = null; InputStream inputStream = null; InputStreamReader inputStreamReader = null; BufferedReader bufferedReader = null; HttpsURLConnection conn = null; try { //创建SSLConrext对象,并使用我们指定的信任管理器初始化 TrustManager[] tm = {new JEEWeiXinX509TrustManager()}; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); //从上述对象中的到SSLSocketFactory SSLSocketFactory ssf = sslContext.getSocketFactory(); System.out.println(path); URL url = new URL(path); conn = (HttpsURLConnection) url.openConnection(); conn.setSSLSocketFactory(ssf); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); //设置请求方式(git|post) conn.setRequestMethod(method); //有数据提交时 if (null != body) { OutputStream outputStream = conn.getOutputStream(); outputStream.write(body.getBytes("UTF-8")); outputStream.close(); } //将返回的输入流转换成字符串 inputStream = conn.getInputStream(); inputStreamReader = new InputStreamReader(inputStream, "UTF-8"); bufferedReader = new BufferedReader(inputStreamReader); String str = null; StringBuffer buffer = new StringBuffer(); while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } response = buffer.toString(); } catch (Exception e) { } finally { if (conn != null) { conn.disconnect(); } try { bufferedReader.close(); inputStreamReader.close(); inputStream.close(); } catch (IOException execption) { } } return response; } } class JEEWeiXinX509TrustManager implements X509TrustManager { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }
2.3>>>接下来,换取access_token,需要说明一下,这里的access_token和基础access_token并不相同,此处指的是专门在网页中使用的access_token,我们暂且称之为web_access_token
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; import com.entity.oDCon; import com.entity.vOpt; import com.entity.vPro; import com.entity.voDet; import com.github.pagehelper.PageInfo; import com.service.VoteOpService; import com.util.Const; import com.util.HttpsUtil; import com.util.UserInfoUtil; @Controller public class IndexController extends BaseController{ @RequestMapping("/vote.do") public ModelAndView listVote(@RequestParam(name="code",required=false)String code, @RequestParam(name="state")String state) { System.out.println("-----------------------------收到请求,请求数据为:"+code+"-----------------------"+state); //通过code换取网页授权web_access_token if(code != null || !(code.equals(""))){ String APPID = Const.appId; String SECRET = Const.appSecret; String CODE = code; String WebAccessToken = ""; String openId = ""; //String nickName,sex,openid = ""; String REDIRECT_URI = "http://qiangqiangchen.55555.io/vote.do"; String SCOPE = "snsapi_userinfo"; String getCodeUrl = UserInfoUtil.getCode(APPID, REDIRECT_URI, SCOPE); System.out.println("---------------getCodeUrl--------------"+getCodeUrl); //替换字符串,获得请求URL String token = UserInfoUtil.getWebAccess(APPID, SECRET, CODE); System.out.println("----------------------------token为:"+token); //通过https方式请求获得web_access_token String response = HttpsUtil.httpsRequestToString(token, "GET", null); JSONObject jsonObject = JSON.parseObject(response); System.out.println("jsonObject------"+jsonObject); if (null != jsonObject) { try { WebAccessToken = jsonObject.getString("access_token"); openId = jsonObject.getString("openid"); System.out.println("获取access_token成功-------------------------"+WebAccessToken+"----------------"+openId); } catch (JSONException e) { WebAccessToken = null;// 获取code失败 System.out.println("获取WebAccessToken失败"); } } } //此处业务代码省略 ^_^ return new ModelAndView("mypages/index", model); } }
至此,我们拿到WebAccessToken、openId,就算完成这一步骤了。
3 :拉取用户信息
3.1>>>在UserInfoUtil中加入:
//拉取用户信息的请求地址 public static String User_Message = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN"; //替换字符串 public static String getUserMessage(String access_token, String openid) { return String.format(User_Message, access_token,openid); }
3.2>>>在IndexController中加入拉取用户信息的代码
@Controller public class IndexController extends BaseController{ //required=false的意思就是可以不传此参数 @RequestMapping("/vote.do") public ModelAndView listVote(@RequestParam(name="code",required=false)String code, @RequestParam(name="state")String state) { System.out.println("-----------------------------收到请求,请求数据为:"+code+"-----------------------"+state); //通过code换取网页授权web_access_token if(code != null || !(code.equals(""))){ String APPID = Const.appId; String SECRET = Const.appSecret; String CODE = code; String WebAccessToken = ""; String openId = ""; String nickName,sex,openid = ""; String REDIRECT_URI = "http://qiangqiangchen.55555.io/vote.do"; String SCOPE = "snsapi_userinfo"; String getCodeUrl = UserInfoUtil.getCode(APPID, REDIRECT_URI, SCOPE); System.out.println("---------------getCodeUrl--------------"+getCodeUrl); //替换字符串,获得请求URL String token = UserInfoUtil.getWebAccess(APPID, SECRET, CODE); System.out.println("----------------------------token为:"+token); //通过https方式请求获得web_access_token String response = HttpsUtil.httpsRequestToString(token, "GET", null); JSONObject jsonObject = JSON.parseObject(response); System.out.println("jsonObject------"+jsonObject); if (null != jsonObject) { try { WebAccessToken = jsonObject.getString("access_token"); openId = jsonObject.getString("openid"); System.out.println("获取access_token成功-------------------------"+WebAccessToken+"----------------"+openId); //-----------------------拉取用户信息...替换字符串,获得请求URL String userMessage = UserInfoUtil.getUserMessage(WebAccessToken, openId); System.out.println(" userMessage==="+ userMessage); //通过https方式请求获得用户信息响应 String userMessageResponse = HttpsUtil.httpsRequestToString(userMessage, "GET", null); JSONObject userMessageJsonObject = JSON.parseObject(userMessageResponse); System.out.println("userMessagejsonObject------"+userMessageJsonObject); if (userMessageJsonObject != null) { try { //用户昵称 nickName = userMessageJsonObject.getString("nickname"); //用户性别 sex = userMessageJsonObject.getString("sex"); sex = (sex.equals("1")) ? "男":"女"; //用户唯一标识 openid = userMessageJsonObject.getString("openid"); System.out.println("用户昵称------------------------"+nickName); System.out.println("用户性别------------------------"+sex); System.out.println("用户的唯一标识-------------------"+openid); } catch (JSONException e) { System.out.println("获取userName失败"); } } } catch (JSONException e) { WebAccessToken = null;// 获取code失败 System.out.println("获取WebAccessToken失败"); } } } return new ModelAndView("mypages/index", model); } }
当启动tomcat后,在手机上打开微信公众号,点击公众号菜单,访问页面,获得用户基本信息的json数据
至此,最初目的已经实现,谢谢你的耐心阅读,大神多批评~本文部分代码参考大神孤傲苍狼所写: 微信开发学习总结
相关文章推荐
- Spring Boot 微信-网页授权获取用户信息
- flask 微信公众号 网页授权获取用户基本信息
- C#微信公众号开发-高级接口-之网页授权oauth2.0获取用户基本信息(二)
- 微信公众号-获取用户信息(网页授权获取)实现步骤
- 微信公众号-获取用户信息(网页授权获取)
- 微信公众号开发《一》OAuth2.0网页授权认证获取用户的详细信息,实现自动登陆
- (微信公众号开发《一》OAuth2.0网页授权认证获取用户的详细信息,实现自动登陆)http://blog.csdn.net/liaohaojian/article/details/70175835
- Django微信公众号开发(一)公众号内网页授权登录后微信获取用户信息
- 微信公众号开发之网页授权(获取用户信息)
- 微信公众号开发《一》OAuth2.0网页授权认证获取用户的详细信息,实现自动登陆
- 微信公众号开发(四)--微信网页授权,获取用户信息
- Java微信公众号开发:网页授权获取用户基本信息
- 微信公众号开发系列-网页授权获取用户基本信息
- Ruby on Rails微信开发4——通过网页授权获取用户的基本信息
- 微信公众号开发之网页授权获取用户基本信息
- 微信公众平台测试号通过网页授权获取用户的信息
- 微信公众号开发-微信网页授权获取用户openid以及用户信息的步骤
- 微信公众号网页授权获取用户基本信息
- 微信公众号开发系列-网页授权获取用户基本信息
- C#微信公众号开发之网页授权oauth2.0获取用户基本信息(一)