小程式登入、微信網頁授權(Java版)
首先呢,“登入”、“授權”、“授權登入”,是一樣的意思,不用糾結。
寫小程式授權登入的程式碼前,需要了解清楚openid與unionid的區別,這裡再簡單介紹一下:
- 騰訊有個 “微信·開放平臺”,只有企業才能註冊賬號,可理解為微信體系裡,最頂級的賬號。官網地址:https://open.weixin.qq.com
- 除了這個微信開放平臺,還有另一個叫做 “微信公眾平臺”,可註冊四種賬號,包括服務號、訂閱號、小程式、企業微信。也就是說,公眾號(服務號和訂閱號可統稱為公眾號)佔一個賬號,小程式也佔一個賬號。在沒有繫結開放平臺前,小程式授權登入只能拿到使用者的openid。官網地址:https://mp.weixin.qq.com
- 小程式可繫結在公眾號下,公眾號可以繫結在微信開放平臺下,小程式也可以繫結在微信開放平臺下。(好像有點小繞)簡單點說,所有的公眾平臺賬號都需要繫結在 “開放平臺” 下,才可獲得的unionid,這是打通同個企業下所有微信公眾賬號的最有效方法(官方推薦)
- 更加具體的可自行百度…
一、以下為小程式登入的程式碼:
-
方式一:通過code呼叫code2session介面獲得message,包含openid、session_key,滿足條件的情況下還能直接獲得unionid
- 條件如下:(存在侷限性)
1/** 2 * Author: huanglp 3 * Date: 2018-11-28 4 */ 5public class WeiXinUtils { 6 7private static Logger log = LoggerFactory.getLogger(WeiXinUtils.class); 8 9/** 10* 通過前端傳過來的code, 呼叫小程式登入介面, 獲取到message並返回 (包含openid session_key等) 11* 12* @param code 13* @return 14*/ 15public static JSONObject login(String code) { 16log.info("==============小程式登入方法開始================"); 17WxMiniProperties properties = WeiXinPropertiesUtils.getWxMiniProperties(); 18String url = properties.getInterfaceUrl() + "/sns/jscode2session?appid=" 19+ properties.getAppId() + "&secret=" + properties.getAppSecret() 20+ "&js_code=" + code + "&grant_type=authorization_code"; 21JSONObject message; 22try { 23// RestTemplate是Spring封裝好的, 挺好用, 可做成單例模式 24RestTemplate restTemplate = new RestTemplate(); 25String response = restTemplate.getForObject(url, String.class); 26message = JSON.parseObject(response); 27} catch (Exception e) { 28log.error("微信伺服器請求錯誤", e); 29message = new JSONObject(); 30} 31log.info("message:" + message.toString()); 32log.info("==============小程式登入方法結束================"); 33return message; 34 35// 後續, 可獲取openid session_key等資料, 以下程式碼一般放在Service層 36//if (message.get("errcode") != null) { 37//throw new ValidationException(message.toString()); 38//} 39//String openid = message.get("openid").toString(); 40//String sessionKey = message.get("session_key").toString(); 41//... 42 43} 44} 複製程式碼
- - 補充1: WeiXinPropertiesUtils工具類
1public class WeiXinPropertiesUtils { 2 3// 微信小程式配置 4private static WxMiniProperties miniProperties; 5// 微信公眾號配置 6private static WxProperties wxProperties; 7 8private static void init() { 9if (miniProperties == null) { 10miniProperties = ContextLoader.getCurrentWebApplicationContext() 11.getBean(WxMiniProperties.class); 12} 13if (wxProperties == null) { 14wxProperties = ContextLoader.getCurrentWebApplicationContext() 15.getBean(WxProperties.class); 16} 17} 18 19public static WxMiniProperties getWxMiniProperties() { 20init(); 21return miniProperties; 22} 23 24public static WxProperties getWxProperties() { 25init(); 26return wxProperties; 27} 28} 複製程式碼
- - 補充2: WxMiniProperties配置類
1@Data 2@Component 3@ConfigurationProperties(prefix = "luwei.module.wx-mini") 4public class WxMiniProperties { 5 6private String appId; 7private String appSecret; 8private String interfaceUrl; 9 10} 複製程式碼
到此已能通過code獲取到使用者的openid和session_key,但若不滿足條件,即使將小程式繫結到微信開放平臺上,也獲取不到unionid,所以此方式不穩定,推薦使用解密的方式獲取資料。
- 方式二:通過解密的方式獲取使用者unionid
1/** 2 * 通過encryptedData,sessionKey,iv獲得解密資訊, 擁有使用者豐富的資訊, 包含openid,unionid,暱稱等 3 */ 4public static JSONObject decryptWxData(String encryptedData, String sessionKey, String iv) throws Exception { 5log.info("============小程式登入解析資料方法開始=========="); 6String result = AesCbcUtil.decrypt(encryptedData, sessionKey, iv, "UTF-8"); 7JSONObject userInfo = new JSONObject(); 8if (null != result && result.length() > 0) { 9userInfo = JSONObject.parseObject(result); 10} 11log.info("result: " + userInfo); 12log.info("============小程式登入解析資料方法結束=========="); 13return userInfo; 14} 複製程式碼
- - 補充1: AesCbcUtil工具類,直接複製即可,需要新增bouncycastle依賴。BouncyCastle是一個開源的加解密解決方案,官網可檢視ofollow,noindex">www.bouncycastle.org/
1package com.luwei.common.utils; 2 3import org.bouncycastle.jce.provider.BouncyCastleProvider; 4import org.apache.commons.codec.binary.Base64; 5import javax.crypto.Cipher; 6import javax.crypto.spec.IvParameterSpec; 7import javax.crypto.spec.SecretKeySpec; 8import java.security.AlgorithmParameters; 9import java.security.Security; 10 11/** 12 * Updated by huanglp 13 * Date: 2018-11-28 14 */ 15public class AesCbcUtil { 16 17static { 18Security.addProvider(new BouncyCastleProvider()); 19} 20 21/** 22* AES解密 23* 24* @param data//被加密的資料 25* @param key//加密祕鑰 26* @param iv//偏移量 27* @param encoding //解密後的結果需要進行的編碼 28*/ 29public static String decrypt(String data, String key, String iv, String encoding) { 30 31// org.apache.commons.codec.binary.Base64 32byte[] dataByte = Base64.decodeBase64(data); 33byte[] keyByte = Base64.decodeBase64(key); 34byte[] ivByte = Base64.decodeBase64(iv); 35 36try { 37Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); 38SecretKeySpec spec = new SecretKeySpec(keyByte, "AES"); 39AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES"); 40parameters.init(new IvParameterSpec(ivByte)); 41 42cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化 43byte[] resultByte = cipher.doFinal(dataByte); 44if (null != resultByte && resultByte.length > 0) { 45return new String(resultByte, encoding); 46} 47return null; 48 49} catch (Exception e) { 50e.printStackTrace(); 51} 52 53return null; 54} 55} 複製程式碼
到此已經獲取到 JSONObject型別的 userInfo,包含openid,unionid,暱稱,頭像等資料
後續可以將使用者資訊儲存到資料庫,再返回給前端一個token即可,shiro經過公司封裝了一層,程式碼如下:
1... 2// 獲得使用者ID 3int userId = wxUser.getWxUserId(); 4shiroTokenService.afterLogout(userId); 5String uuid = UUID.randomUUID().toString(); 6String token = StringUtils.deleteAny(uuid, "-") + Long.toString(System.currentTimeMillis(), Character.MAX_RADIX); 7shiroTokenService.afterLogin(userId, token, null); 8return token; 複製程式碼
二、以下為公眾號(網頁)授權的程式碼:
網頁授權更加簡單,可檢視官方文件
需新增 riversoft 相關依賴包,公眾號網頁授權,只需要將公眾號綁定了開放平臺,就能獲取到unionid及其他使用者資訊。
1public static OpenUser webSiteLogin(String code, String state) { 2log.info("============微信公眾號(網頁)授權開始==========="); 3WxProperties properties = WeiXinPropertiesUtils.getWxProperties(); 4AppSetting appSetting = new AppSetting(properties.getAppId(), properties.getAppSecret()); 5OpenOAuth2s openOAuth2s = OpenOAuth2s.with(appSetting); 6AccessToken accessToken = openOAuth2s.getAccessToken(code); 7 8// 獲取使用者資訊 9OpenUser openUser = openOAuth2s.userInfo(accessToken.getAccessToken(), accessToken.getOpenId()); 10log.info("============微信公眾號(網頁)授權結束==========="); 11return openUser; 12 13// 後續, 可將使用者資訊儲存 14// 最後一步, 生成token後, 需重定向回頁面 15//return "redirect:" + state + "?token=" + token; 16} 複製程式碼
以下就是本人整理的關於微信公眾號授權和小程式授權的一些經驗和問題彙總,希望大家能夠從中獲得解決方法。