在我以前的一篇博客中讲到了获取openid的方法,这里就不做过多的讲解java获取微信小程序openid。这里主要讲解微信小程序登陆的实现和获取unionid。需要提醒的是我后端框架使用的是jFinal,传值方式跟spring的那套有些许的差别。
1、首先要知道微信小程序的开发本身就是基于微信端的开发,可以算是跨域的一种操作,官方推荐的后端语言是node.js和php,这里用到的服务器语言是java,开始
2、这里引用一张图片是来自于https://blog.csdn.net/yelin042/article/details/71773636这篇博主的文章,当然我使用的登陆功能是使用redis存储。
自认为这个登陆的讲解还是比较详细的。首先理解思路,很简单在登陆成功了以后再java端把用户的信息保存在redis然后生成的key传到小程序端保存起来,在下次需要使用用户信息的时候从小程序的缓存中查找,然后去java端查询用户信息,记得是先从redis中查询
3、首先是java端代码
public void auth() {
Cache bbs = Redis.use();
int loginid = getParaToInt("loginid", 0);
//根据小程序端传过来的缓存id,这个id是在java端生成的id
BuyerUser buyerU = bbs.get(loginid);
if (buyerU == null) {
String grant_type = "authorization_code";
//URL
String requestUrl = "https://api.weixin.qq.com/sns/jscode2session?";
String code = getPara("js_code");
String encryptedData = getPara("encryptedData");
String iv = getPara("iv");
//请求参数
String params = "appid=" + AppId + "&secret=" + AppSecret + "&js_code=" + code + "&grant_type=" + grant_type;
//发送请求
String data = HttpUtils.get(requestUrl + params);
//解析相应内容(转换成json对象)
JSONObject json = JSONObject.fromObject(data);
//用户的唯一标识(openid),这里需要一个解密,下面会说明怎么进行解密的
String Openid = String.valueOf(json.get("openid"));
com.alibaba.fastjson.JSONObject ins = WXUtils.getUserInfo(encryptedData, String.valueOf(json.get("session_key")), iv);
System.out.println(ins + "-=-=-=-=-=-=-");
String unionId = String.valueOf(ins.get("unionId"));
BuyerUser user = BuyerUser.dao.findFirst("select * from " + BuyerUser.TABLE_NAME + " where unionid=?", unionId);
if (user == null) {
//用户信息保存在数据库中
BuyerUser buyerUser = new BuyerUser();
buyerUser.save();
bbs.set(buyerUser.getId(), buyerUser);
setAttr("loid", buyerUser.getId());
} else {
//更新缓存
user.setUnionid(unionId);
user.update();
// bbs.hset(CACHE_NAME, user.getId(), user);
bbs.set(user.getId(), user);
setAttr("loid", user.getId());
}
// index();
} else {
}
renderJson();
}
4、上面代码中牵扯到union的一个解密,这里需要提示一下union的获取途径,我所使用的是微信开放平台绑定小程序,因为公司牵扯到好几个公众号需要用户信息统一所以使用开放平台保证信息的统一
5、uninon解密,需要导几个包
net.sf.json-lib
json-lib
2.4
jdk15
org.codehaus.xfire
xfire-core
1.2.6
org.bouncycastle
bcprov-jdk16
1.46
代码
public class WXUtils {
public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv){
// 被加密的数据
byte[] dataByte = Base64.decode(encryptedData);
// 加密秘钥
byte[] keyByte = Base64.decode(sessionKey);
// 偏移量
byte[] ivByte = Base64.decode(iv);
try {
// 如果密钥不足16位,那么就补足. 这个if 中的内容很重要
int base = 16;
if (keyByte.length % base != 0) {
int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
byte[] temp = new byte[groups * base];
Arrays.fill(temp, (byte) 0);
System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
keyByte = temp;
}
// 初始化
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC");
SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
parameters.init(new IvParameterSpec(ivByte));
cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
byte[] resultByte = cipher.doFinal(dataByte);
if (null != resultByte && resultByte.length > 0) {
String result = new String(resultByte, "UTF-8");
return JSONObject.parseObject(result);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
6、小程序端,只写核心代码,这里需要讲解一个我里面的ht代码我的域名,这里需要自己解决 ,开个内网映射都行然后把微信开发者工具里面的https校验去掉就ok啦。
// 查看是否授权
wx.getSetting({
success: function(res) {
if (res.authSetting['scope.userInfo']) {
//用户已经授权过,直接跳转到主页面就可以啦
wx.reLaunch({
url: '../index/index',
success: function(res) {
// console.log("调用成功")
},
fail: function(res) {
// console.log("调用失败")
}
});
var that = this;
//已经失效重新登录获取
wx.login({
success: function (ress) {
wx.getUserInfo({
success: function (res) {
//从缓存中读取缓存的key
wx.getStorage({
key: 'loginid',
success: function (resp) {
// console.log("查看目前的loginid:" + resp.data)
},
//第一次进入小程序肯定是失败的
fail: function () {
wx.request({
url: ht + '/auth.html',
data: {
encryptedData: res.encryptedData,
iv: res.iv,
js_code: ress.code,
loginid: 0
},
method: 'GET',
success: function (resd) {
//console.log(resd.data.loid + "登录的id")
// console.log(res.data.openid)
//把rediskey保存在小程序的缓存中
wx.setStorage({
key: 'loginid',
data: resd.data.loid,
})
//保存缓存以后重新刷新页面就可以获取到缓存中id后台查询数据
// wx.reLaunch({
// url: '../index/index',
// success: function (res) {
// console.log("调用成功")
// },
// fail: function (res) {
// console.log("调用失败")
// }
// })
},
fail: function () {
// console.log("拉去用户信息失败")
}
})
}
})
},
fail: function (res) {
// console.log("获取用户信息失败")
}
});
}
})
} else {
// console.log("还没有授权")
}
}
})