preface
The company has recently developed a program. The requirement is to obtain customer ID from the database through the user's mobile phone number, and carry out the following series of operations according to customer ID. Here is a summary of the experience:
1. Authorization to obtain ciphertext
according to Official documents of wechat applet To obtain the encrypted ciphertext of the mobile phone number, you must call back through the bindetphonenumber event of the button component. Therefore, there are three ways to authorize according to different needs:
①. Set the first page as the authorization page
The first time the user enters the applet, let the user authorize first, otherwise he can't jump to other pages. After obtaining CUSTOMERID, he can save it to the local user. The next time he logs in to the applet, he doesn't need to authorize again.
② Obtain authorization on the login page
Set two button components on the login page. Add the boolean variable isLogin in the data of the background JS, which is false by default. After the background obtains CUSTOMERID, set isLogin to true in the success callback function, so that only one of the two button components will appear before and after authorization.
<button wx:if="{{isLogin}}" class="next-step" bindtap="login">next step</button> <button wx:else class="next-step" open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">to grant authorization</button>
③ Bottom navigation bar "my"
Set the login button on this page, which is also the method adopted by most applets.
After clicking the authorization button and agreeing, a large string of encrypted ciphertext encryptedData and the initial vector iv of the encryption algorithm will be obtained as follows:
2. Get the key
Use Wx. In the API provided by the applet Login method to obtain the temporary login certificate code, and then access the interface address provided by wechat to obtain the key session_key.
https://api.weixin.qq.com/sns/jscode2sessionappid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
PS: of APPID and SECRET Get link , you can view it after logging in.
Fill in the parameters in the corresponding position and send the GET request. After success, the session will be returned_ key. The code is as follows:
wx.login({ success: function (res) { wx.request({ url: 'https://api.weixin.qq.com/sns/jscode2session?appid=wx9*****ff540c64e&secret=3fd147f9e24******738bb84fae30be&js_code=' + res.code + '&grant_type=authorization_code', success: function (res) { wx.setStorageSync('key', res.data.session_key) } }) } })
PS: it is not recommended to write in this way. The official document also says not to use session_ When the key is sent to the front end, you should request the API address in your own server, and then return the mobile phone number information after decryption.
3. Decryption
Decryption requires a dependent class. Maven is as follows:
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk16</artifactId> <version>1.46</version> </dependency>
Pass the currently obtained ciphertext, key and initial vector into the background.
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.security.Key; import java.security.Security; import java.util.Arrays; import static org.bouncycastle.util.encoders.Base64.decode; import org.bouncycastle.jce.provider.BouncyCastleProvider; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; @RestController @RequestMapping("/user") public class UserController { private static final String KEY_ALGORITHM = "AES"; private static final String ALGORITHM_STR = "AES/CBC/PKCS7Padding"; private static Key key; private static Cipher cipher; @RequestMapping("getPhoneNumber") public String getPhoneNumber(String encryptedData,String key,String iv) { String data = decryptData(encryptedData, key, iv); JSONObject jsonObject = JSON.parseObject(data); String phoneNumber = jsonObject.get("phoneNumber").toString(); return phoneNumber; } public static String decryptData(String encryptDataB64, String sessionKeyB64, String ivB64) { return new String( decryptOfDiyIV( decode(encryptDataB64), decode(sessionKeyB64), decode(ivB64) ) ); } /** * Decryption method * * @param encryptedData String to decrypt * @param keyBytes decryption key * @param ivs User defined symmetric decryption algorithm initial vector iv * @return Decrypted byte array */ private static byte[] decryptOfDiyIV(byte[] encryptedData, byte[] keyBytes, byte[] ivs) { byte[] encryptedText = null; init(keyBytes); try { cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivs)); encryptedText = cipher.doFinal(encryptedData); } catch (Exception e) { e.printStackTrace(); } return encryptedText; } } private static void init(byte[] keyBytes) { // If the key is less than 16 bits, supplement it The content in this if is very important int base = 16; if (keyBytes.length % base != 0) { int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0); byte[] temp = new byte[groups * base]; Arrays.fill(temp, (byte) 0); System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length); keyBytes = temp; } // initialization Security.addProvider(new BouncyCastleProvider()); // Key format converted to JAVA key = new SecretKeySpec(keyBytes, KEY_ALGORITHM); try { // Initialize cipher cipher = Cipher.getInstance(ALGORITHM_STR, "BC"); } catch (Exception e) { e.printStackTrace(); } }
PS: code reference author @His name is sun ran
Note: the decrypted data obtained according to the above method is a JSON format string, which needs to be converted into a JSON object to get the phonenumber inside
The results are as follows: