我对接公众号,主要使用的地方在H5。实现效果就是不需要关注公众号就会弹出来一个授权页,然后进行其他的一些操作。
效果图:
其实代码很简单,主要是这个流程。我先讲流程,再结合代码,请仔细看完,绝对可以完成。
- 请求微信授权接口(分为静默模式和非静默模式)
- 在第一步的基础上会有一个回调地址redirect_uri,这里就是写我们自己的登录逻辑和获取用户信息
其实就完了。。。。
一、请求微信授权接口
https://open.weixin.qq.com/connect/oauth2/authorize?appid={APPID}&redirect_uri=https://c380h47694.vicp.fun//wechat/login&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect
主要几个参数:
- appid 微信公众号)appid
- redirect_uri 回调地址)就是你的接口
- response_type 固定写死的
- scope 类型这个参数就很重要了
- snsapi_userinfo:非静默模式,就是像上图一样会弹出授权页
- snsapi_base:静默模式
二、编写回调接口
主要就是获取网页授权token和用户信息接口,需要注意有几个获取用户信息的url,不要用错了 网页授权是用这个获取
/** 获取网页授权access_token的URL,和基础服务access_token不同 **/
private final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=APPSECRET&code=CODE&grant_type=authorization_code";
/** 用户信息URL**/
private final static String USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
/**
* 网页授权AccessToken
* @param code 微信传递的code
* @return json
*/
private static JSONObject geOauth2AccessToken(String code) {
String requestUrl = ACCESS_TOKEN_URL.replace("APPID", APPID).replace("APPSECRET", SECRET).replace("CODE",code);
// 发起GET请求获取凭证
String result = HttpUtil.get(requestUrl);
log.info(result);
JSONObject jsonObject = JSONUtil.parseObj(result);
if (Objects.nonNull(jsonObject.getInt(ERR_CODE))) {
throw new CustomException("网页授权AccessToken失败:"+jsonObject);
}
return jsonObject;
}
/**
* 获取用户信息
* // 用户的标识
* System.out.println(jsonObject.getStr("openid"));
* // 关注状态(1是关注,0是未关注),未关注时获取不到其余信息
* System.out.println(jsonObject.getInt("subscribe"));
* // 用户关注时间
* System.out.println(jsonObject.getStr("subscribe_time"));
* // 昵称
* System.out.println(jsonObject.getStr("nickname"));
* // 用户的性别(1是男性,2是女性,0是未知)
* System.out.println(jsonObject.getInt("sex"));
* // 用户所在国家
* System.out.println(jsonObject.getStr("country"));
* // 用户所在省份
* System.out.println(jsonObject.getStr("province"));
* // 用户所在城市
* System.out.println(jsonObject.getStr("city"));
* // 用户的语言,简体中文为zh_CN
* System.out.println(jsonObject.getStr("language"));
* // 用户头像
* System.out.println(jsonObject.getStr("headimgurl"));
* @param accessToken 接口访问凭证 全局访问token
* @param openId 用户标识
* @return WeixinUserInfo
*/
public static JSONObject getUserInfo(String accessToken, String openId) {
// 拼接请求地址
String requestUrl = USER_INFO_URL.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
// 获取用户信息
String result = HttpUtil.get(requestUrl);
log.info("获取用户信息结果:"+result);
JSONObject jsonObject = JSONUtil.parseObj(result);
return jsonObject;
}
三、公众号配置
完事!!!
编写获取微信签名
用的是hutool工具类生成的随机数
应该复制过去能直接用,不过有些不重要的代码没有贴,随便改改写死就行
@ApiOperation(value = "获取微信签名")
@GetMapping("/getWXSign")
public Result<String> getWXSign(@ApiParam("当前地址") String url) {
long timeStampSec = System.currentTimeMillis() /1000;
String timestamp = String.format("%010d", timeStampSec);
String nonceStr = RandomUtil.randomString(8);
String[] urls = url.split("#");
String newUrl = urls[0];
JSONObject respJson =new JSONObject();
String wxJsapiTicket = WechatUtil.getWXJsapiTicket();
System.out.println("ticket:"+wxJsapiTicket);
String[] paramArr =new String[]{"url=" + newUrl,"jsapi_ticket=" + wxJsapiTicket,"noncestr=" + nonceStr,"timestamp=" + timestamp};
Arrays.sort(paramArr);
// 将排序后的结果拼接成一个字符串
String content = paramArr[0].concat("&").concat(paramArr[1]).concat("&").concat(paramArr[2]).concat("&").concat(paramArr[3]);
String signature = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
// 对接后的字符串进行sha1加密
byte[] digest = md.digest(content.toString().getBytes());
signature = WechatUtil.byteToStr(digest).toLowerCase();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
respJson.put("appId", WechatUtil.APPID);
respJson.put("timestamp", timestamp);
respJson.put("nonceStr", nonceStr);
respJson.put("signature", signature);
return Result.newSuccess(respJson.toJSONString());
}
/**
* 获取基础服务接口访问凭证
* @return token 基础token
*/
public static String getAccessToken() {
String accessToken;
RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
Object accessTokenCache = redisUtil.get(CommonConstant.ACCESS_TOKEN);
if (Objects.nonNull(accessTokenCache)) {
accessToken = accessTokenCache.toString();
return accessToken;
}
String requestUrl = TOKEN_URL.replace("APPID", APPID).replace("APPSECRET", SECRET);
// 发起GET请求获取凭证
String result = HttpUtil.get(requestUrl);
log.info("全局获取token接口返回参数:"+result);
JSONObject jsonObject = JSONUtil.parseObj(result);
if (Objects.nonNull(jsonObject.getInt(ERR_CODE))) {
throw new CustomException("获取用户信息失败,请重试");
}
accessToken = jsonObject.getStr("access_token");
redisUtil.set(CommonConstant.ACCESS_TOKEN,accessToken);
return accessToken;
}
/**
* 入参为token,返回ticket
* @return
*/
public static String getWXJsapiTicket() {
String accessToken = getAccessToken();
String tokenUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessToken+"&type=jsapi";
String result = HttpUtil.get(tokenUrl);
com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(result);
return jsonObject.getString("ticket");
}
/**
* 编码sign
* @param byteArray sign
* @return 字符串
*/
public 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;
}
遇到的坑
- 切换测试公众号和真实公众号的时遇到的缓存或者没切换