700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Java后台获取微信小程序用户信息

Java后台获取微信小程序用户信息

时间:2020-10-19 11:49:50

相关推荐

Java后台获取微信小程序用户信息

我们在开发微信小程序时经常需要获取用户微信用户名以及头像信息,微信提供了专门的接口API用于返回这些信息,但是与接口获取接口需要经过许多验证步骤,现在记录如下。

1、接口校验

只有通过微信平台验证的域名才能访问微信接口,微信公众号会发送请求到我们指定的URL,我们需要作出正确的响应才能通过验证。

登录微信测试号管理页面:https://mp./debug/cgi-bin/sandbox?t=sandbox/login

如下所示,每个微信号会分配一个测试号,对应appID,其密码为appsecret

在接口配置信息中填写验证发往的URL,并约定好Token,这里点击提交会验证失败,因为我们还没有在服务器编写对请求的响应。。

微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示

服务器端的验证过程如下:

将token、timestamp、nonce三个参数进行字典序排序将三个参数字符串拼接成一个字符串进行sha1加密将加密后的字符串可与signature对比,若相同则验证成功,并且将echostr原样返回

如下所示对请求“ShopDemo/WxVerifier”作出响应,获取GET请求中的参数并传入WxSignUtil.checkSignature()方法中进行校验,若校验成功则原样返回echostr

@Controller@RequestMapping("WxVerifier")public class VerifyController {private static Logger log = LoggerFactory.getLogger(VerifyController.class);@RequestMapping(method = {RequestMethod.GET})public void doGet(HttpServletRequest request, HttpServletResponse response) {log.debug("weixin get...");String signature = request.getParameter("signature"); // 加密签名String timestamp = request.getParameter("timestamp"); // 时间戳String nonce = request.getParameter("nonce"); // 随机数String echostr = request.getParameter("echostr"); // 随机字符串PrintWriter out = null;try {out = response.getWriter();// 通过检验signature对请求进行校验if (WxSignUtil.checkSignature(signature, timestamp, nonce)) {log.debug("weixin get success...."); out.print(echostr);//校验成功则原样返回echostr}} catch (IOException e) {e.printStackTrace();} finally {if (out != null)out.close();}}}

如下实现校验方法WxSignUtil.checkSignature()。对三个参数进行排序,加密然后比对,返回校验结果

public class WxSignUtil {private static String token = "shopdemo";//约定好的token//验证签名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;}//将字节数组转换为十六进制字符串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、获取用户信息

在测试号管理页面中找到“体验接口权限表”,在其中找到网页服务->网页账号,点击后面的修改,填写授权回调页面域名。这里的域名可以是域名或者IP地址,例如、39.99.252.77,域名授权之后,域名下的子页面就可以访问微信API获取用户信息。

注意前面不要有“http://”等协议头,否则会提示"该链接无法访问,code -1"。

接下来获取用户信息,一共分为3步。

1、获取用户授权code

在微信或者微信开发者工具中访问如下网页链接,用户确认授权后会携带授权code跳转到重定向页面http://39.99.152.77/ShopDemo/wechatlogin/check

https://open./connect/oauth2/authorize?appid=wx691fee528cce2991&redirect_uri=http://39.99.152.77/ShopDemo/wechatlogin/check&role_type=1&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect

其中

appID为公众号的唯一标识redirect_uri是用户授权成功后重定向的回调地址,应该是授权域名的子页面response_type 返回类型,这里需要返回codescope应用授权作用域,这里选择snsapi_userinfo类型,它会弹出授权页面,可通过openid拿到昵称、性别、所在地等信息state为用户重定向传递的参数#wechat_redirect无论直接打开还是重定向,必须带此参数

2、通过code换取网页授权access_token

在重定向的地址中,根据请求链接中code,并且结合appIDappSecret去访问微信的如下接口获取access_token

https://api./sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

若成功将以json的格式返回结果,其字段如下:

3、拉取用户信息

根据上一步拿到的access_tokenopenid,再次访问的如下微信接口从而获取到用户的具体信息

https://api./sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

成功后将以JSON格式返回用户信息如下:

{"openid":"o-i6Uswvm5012blk7EGOu6TlM","nickname":"Tory","sex":1,"language":"zh_CN","city":"北京","province":"北京","country":"中国","headimgurl":"/mmopen/vi_32/qe7I5uxq9dKEmSv88osAfAiblI61jmjLBIDicbicVEib53RPJTKoZQL7JuVNZdfjjcBZj9Z0c2VkA/132","privilege":[]}

上述步骤代码实现如下,即定义路由完成对重定向“/wechatlogin/check”请求的响应,获取到用户信息后再跳转到"front/index"页面。

在其中使用LoggerFactory进行调试信息的输出,将请求到的token、用户信息保存到日志,输出结果在tomcat/logs/webapps/debug.log文件中

@Controller@RequestMapping("wechatlogin")public class LoginController {private static Logger log = LoggerFactory.getLogger(LoginController.class);@RequestMapping("check")public String doGet(HttpServletRequest request, HttpServletResponse response) {log.debug("weixin login get...");// 1、获取微信公众号传输过来的codeString code = request.getParameter("code");log.debug("weixin login code:" + code);WechatUser user = null;String openId = null;if (null != code) {WXAccessToken token;try {// 2、通过code获取access_tokentoken = WechatUtil.getUserAccessToken(code);log.debug("weixin login token:" + token.toString());String accessToken = token.getAccessToken();openId = token.getOpenId();// 3、通过access_token和openId获取用户昵称等信息user = WechatUtil.getUserInfo(accessToken, openId);log.debug("weixin login user:" + user.toString());request.getSession().setAttribute("openId", openId);} catch (IOException e) {log.error("error in getUserAccessToken or getUserInfo or findByOpenId: " + e.toString());e.printStackTrace();}}if (user != null) {// 获取到微信用户信息后跳转到到指定的页面return "front/index";} else {return null;}}}

获取AccessToken对象

在上面的代码中用到了WechatUtil.getUserAccessToken()方法来获取并构建AccessToken对象,其实现方法非常经典,记录如下。

首先根据appId、appsecret、code拼接成获取Token的URL,然后通过httpsRequest()向URL发送请求并获取到json格式的token。接下来通过ObjectMapper.readValue()方法将json映射为WXAccess对象并返回。

public static WXAccessToken getUserAccessToken(String code) throws IOException {String appId = "wx691fee528cce2991";String appsecret = "cb17a213ba780f1425da5aa7d157c2c";// 拼接获取AccessToken的URLString url = "https://api./sns/oauth2/access_token?appid=" + appId + "&secret=" + appsecret+ "&code=" + code + "&grant_type=authorization_code";// 向相应URL发送请求获取tokenString tokenStr = httpsRequest(url, "GET", null);log.debug("userAccessToken:" + tokenStr);WXAccessToken token = new WXAccessToken();ObjectMapper objectMapper = new ObjectMapper();try {// 将json字符串映射为对象token = objectMapper.readValue(tokenStr, WXAccessToken.class);} catch (JsonParseException e) {log.error("转换用户accessToken失败: " + e.getMessage());e.printStackTrace();}if (token == null) {log.error("获取用户accessToken失败。");return null;}return token;}

JSON并不是任意对象都能直接映射,需要在定义WXAcess类时通过@JsonProperty()注解来标记属性与json字段之间的对应关系,这样json字符串才能正确映射为Java对象

public class WXAccessToken {// 获取到的凭证@JsonProperty("access_token")private String accessToken;// 凭证有效时间,单位:秒@JsonProperty("expires_in")private String expiresIn;// 表示更新令牌,用来获取下一次的访问令牌,这里没太大用处@JsonProperty("refresh_token")private String refreshToken;// 该用户在此公众号下的身份标识,对于此微信号具有唯一性@JsonProperty("openid")private String openId;// 表示权限范围,这里可省略@JsonProperty("scope")private String scope;//getter and setter...}

WechatUtil.getUserInfo()的实现与上面获取AccessToken对象的过程相同,在拿到token之后向指定URL发送请求获取JSON格式的用户信息,通过ObjectMapper映射为WechatUser对象。

如下所示为微信用户对象WechatUser

public class WechatUser implements Serializable {// openId,标识该公众号下面的该用户的唯一Id@JsonProperty("openid")private String openId;// 用户昵称@JsonProperty("nickname")private String nickName;// 性别@JsonProperty("sex")private int sex;// 省份@JsonProperty("province")private String province;// 城市@JsonProperty("city")private String city;// 区@JsonProperty("country")private String country;// 头像图片地址@JsonProperty("headimgurl")private String headimgurl;// 语言@JsonProperty("language")private String language;// 用户权限,这里没什么作用@JsonProperty("privilege")private String[] privilege;//...getter and setter}

如下所示为getUserInfo()方法,通过访问接口获取json字符,然后通过ObjectMapper映射为WechatUser对象并返回。这样我们就获取到了微信用户对象。

public static WechatUser getUserInfo(String accessToken, String openId) {// 根据传入的accessToken以及openId拼接出访问微信定义的端口并获取用户信息的URLString url = "https://api./sns/userinfo?access_token=" + accessToken + "&openid=" + openId+ "&lang=zh_CN";// 访问该URL获取用户信息json 字符串String userStr = httpsRequest(url, "GET", null);log.debug("user info :" + userStr);WechatUser user = new WechatUser();ObjectMapper objectMapper = new ObjectMapper();try {// 将json字符串转换成相应对象user = objectMapper.readValue(userStr, WechatUser.class);} catch (IOException e) {log.error("获取用户信息失败: " + e.getMessage());e.printStackTrace();}if (user == null) {log.error("获取用户信息失败。");return null;}return user;}

发送HTTPS请求

在获取token和用户信息时都用到了httpsRequest()发送,其实现如下所示,利用SSLContext加密的HttpsURLConnection来发送https请求

/*** 发起https请求并获取结果** @param requestUrl 请求地址* @param requestMethod 请求方式(GET、POST)* @param outputStr提交的数据* @return 返回的json字符串*/public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {StringBuffer buffer = new StringBuffer();try {// 创建SSLContext对象,并使用我们指定的信任管理器初始化TrustManager[] trustManagers = {new MyX509TrustManager()};SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");sslContext.init(null, trustManagers, new java.security.SecureRandom());// 从上述SSLContext对象中得到SSLSocketFactory对象SSLSocketFactory ssf = sslContext.getSocketFactory();URL url = new URL(requestUrl);HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();httpUrlConn.setSSLSocketFactory(ssf);httpUrlConn.setDoOutput(true);httpUrlConn.setDoInput(true);httpUrlConn.setUseCaches(false);// 设置请求方式(GET/POST)httpUrlConn.setRequestMethod(requestMethod);if ("GET".equalsIgnoreCase(requestMethod))httpUrlConn.connect();// 当有数据需要提交时if (null != outputStr) {OutputStream outputStream = httpUrlConn.getOutputStream();// 注意编码格式,防止中文乱码outputStream.write(outputStr.getBytes("UTF-8"));outputStream.close();}// 将返回的输入流转换成字符串InputStream inputStream = httpUrlConn.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String str = null;while ((str = bufferedReader.readLine()) != null) {buffer.append(str);}// 释放资源bufferedReader.close();inputStreamReader.close();inputStream.close();inputStream = null;httpUrlConn.disconnect();log.debug("https buffer:" + buffer.toString());} catch (ConnectException ce) {log.error("Weixin server connection timed out.");} catch (Exception e) {log.error("https request error:{}", e);}//最后将获取到的数据返回return buffer.toString();}

其中用到了自定义的证书信任管理器MyX509TrustManager,只是简单实现了X509TrustManager接口

public class MyX509TrustManager 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;}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。