小程序开发(1)——授权登录
最近公司在做小程序项目,第一次接触小程序开发,踩了很多坑,整理了一些常见问题,分享给大家。今天先总结一下微信小程序单点登录:
微信官方登陆流程图:
我的登录流程:
小程序登录主要流程
1小程序发起登陆请求,调用wx.login()获取临时登陆凭证code。请求至后台。
2 通过code调用微信接口换取用户唯一标识openid和会话秘钥session_key
3 自己生成一个唯一标识3rd_session作为key,使用openid和session_key组合加密作为value保存至缓存(可以使用redis作为缓存)。
4.根据业务需求处理微信用户信息。
5 后台返回给小程序端key值,作为登录状态(可以保存至微信缓存,也可以定义成全局变量)。
6.后续请求如果需要openid,小程序端获取key,,请求至后台在后台缓存中获取openid。
小程序端主要代码
1bindGetUserInfo: function bindGetUserInfo(e) {
2 var that = this;
3 if (e.detail.userInfo) {
4 wx.login({
5 success: function success(loginRes) {
6 if (loginRes) {
7 //获取用户信息
8 wx.getUserInfo({
9 withCredentials: true, //非必填 默认为true
10 success: function success(infoRes) {
11 //请求服务端的登录接口
12 wx.request({
13 url: app.globalData.url + "LoginController",
14 data: {
15 code: loginRes.code, //临时登录凭证
16 rawData: infoRes.rawData, //用户非敏感信息
17 signature: infoRes.signature, //签名
18 encrypteData: infoRes.encryptedData, //用户敏感信息
19 iv: infoRes.iv //解密算法的向量
20 },
21 success: function success(res) {
22 console.log("login success");
24 app.globalData.sessionid = res.data.sessionId;
26 wx.setStorageSync("sessionid", res.data.sessionId);
27 that.util("close");
28 }
29 });
30 }
31 });
32 }
33 }
34 });
35
36 //授权成功后,跳转进入小程序首页
37 } else {
38 //用户按了拒绝按钮
39 wx.showModal({
40 title: "提示",
41 content: "拒绝授权,将无法提供部分服务哦!",
42 showCancel: false,
43 success: function success(res) {
44 that.util("close");
45 }
46 });
47 }
48 }
参数解释:
code:loginRes.code,//临时登录凭证:必传,通过code来换取后台的sessionKey和openId
rawData:infoRes.rawData,//用户非敏感信息
signature:infoRes.signature,//签名
encrypteData:infoRes.encryptedData,//用户敏感信息
iv:infoRes.iv//解密算法的向量
Java后端主要代码
1 控制层
1String iv = request.getParameter("iv");
2 String encrypteData = request.getParameter("encrypteData");
3 String APPID = Utility.getSysParameter("WeChatAppID");
4 String SECRET = Utility.getSysParameter("appSecret");
5
6 String grant_type = "authorization_code";
7 // 微信官方获取openid接口
8 String WX_URL = "https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code";
9 String requestUrl = WX_URL.replace("APPID", APPID)
10 .replace("SECRET", SECRET).replace("JSCODE", code)
11 .replace("authorization_code", grant_type);
12 String returnvalue =WxUtils.getDataByUrl(code);
13 JSONObject jo = JSONObject.fromObject(returnvalue);
14 String openid = (String) jo.get("openid");
15 String session_key = (String) jo.get("session_key");
16 //解密用户信息
17 byte[] bytes = null;
18 try {
19 bytes = decrypt(Base64.decodeBase64(session_key.getBytes()),
20 Base64.decodeBase64(iv.getBytes()),
21 Base64.decodeBase64(encrypteData.getBytes()));
22 } catch (Exception e) {
23 e.printStackTrace();
24 }
25 String userinfo = new String(bytes, "UTF8");
26 //保存用户信息
27 JSONObject jsonObject = JSONObject.fromObject(userinfo);
28 insertUser(jsonObject, openid);
29 try {
30 Registeredusers(jsonObject,openid);
31 } catch (Exception e) {
32 e.printStackTrace();
33 }
34 Jedis jedis = redisUtil.getJedis();
35 //清除以前缓存
36 if (jedis.hexists("TODELETE",openid)) {
37 String oldSesssionId = jedis.hget("TODELETE",openid);
38 jedis.hdel("TODELETE",openid);
39 if(jedis.hexists("SessionAndOpenId",oldSesssionId)){
40 jedis.hdel("SessionAndOpenId",oldSesssionId);
41 }
42 }
43 //redis缓存openid以及sessionkey
44 String sessionId = UUID.randomUUID().toString().replaceAll("-", "");
45 jedis.hset("TODELETE", openid, sessionId);
46 jedis.hset("SessionAndOpenId", sessionId, openid+sessionId+session_key);
47 JSONObject jsonObject2 = new JSONObject();
48 jsonObject2 .put("sessionId", sessionId);
49 //将用户信息返回至小程序端
使用redis维护sessionid
维护3rd_session需要一个内存数据库,这里我选用了redis
维护会话态是内存数据库的典型应用场景,毕竟量小,并且要求速度快,这么一个小应用,当然也可以自己在内存中维护一个对象来进行会话id的处理,但是肯定难以跟一个成熟的系统相媲美
抛开代码实现,这似乎就是一句话可以概括的事情,生成一个唯一的随机串sessionid,以此为key,openid和微信方的session_key为value存入redis,并把sessionid传回给客户端。
2工具类
1/**
2 * <p>Title: getDataByUrl</p>
3 * <p>Description:使用微信开放接口获取openid和sessionkey </p>
4 * @param url
5 * @return
6 */
7 public static String getDataByUrl(String url) {
8 String result = "";
9 BufferedReader in = null;
10 InputStream is = null;
11 InputStreamReader isr = null;
12 try {
13 URL realUrl = new URL(url);
14 URLConnection conn = realUrl.openConnection();
15 conn.connect();
16 is = conn.getInputStream();
17 isr = new InputStreamReader(is);
18 in = new BufferedReader(isr);
19 String line;
20 while ((line = in.readLine()) != null) {
21 result += line;
22 }
23 } catch (Exception e) {
24 e.printStackTrace();
25 } finally {
26 try {
27 if (in != null)in.close();
28 if (is != null)is.close();
29 if (isr != null)isr.close();
30 } catch (Exception ex) {
31 ex.printStackTrace();
32 }
33 }
34 return result;
35 }
36 /**
37 * <p>Title: decrypt</p>
38 * <p>Description: 解密微信用户敏感信息 </p>
39 * @param sessionkey
40 * @param iv
41 * @param encryptedData
42 * @return
43 * @throws Exception
44 */
45 public static byte[] decrypt(byte[] sessionkey, byte[] iv,byte[] encryptedData) throws Exception {
46 AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
47 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
48 SecretKeySpec keySpec = new SecretKeySpec(sessionkey, "AES");
49 cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
50 return cipher.doFinal(encryptedData);
51 }
一结语
小程序登录相对灵活,可根据自己实际业务需求,进行代码设计。
扫一扫,关注Java开发之美,获取更多视频书籍资料