记一次微信小程序+springboot获取用户手机号码
参考了一份demo 但是不知道出处。很尴尬。
一、首先使用mpvue+vant搭建一个简单的前端
<template>
<van-dialog
title="获取手机号码"
message="牛儿洗护订单详情要求获取您的手机号码"
:show="isLoginShow"
show-cancel-button
confirm-button-open-type="getPhoneNumber"
@getphonenumber="getPhoneNumber"
@confirm="onConfirm"
@cancel="onCancel"
>
</van-dialog>
</template>
注:这里通过getphoneNumber方法去实现具体逻辑。
confirm-button-open-type="getPhoneNumber"
注意一定要将这个属性配置为getPhoneNumber否则无法获取解密所需的参数
二、实现getphoneNumber方法
getPhoneNumber (e) {
// 将this赋给_this已供全局使用
const _this = this;
// console.log(_this.code)
// console.log(e.mp.detail.iv)
// console.log(e.mp.detail.encryptedData)
// 需要先执行微信小程序原生的登录方法去获取 code。
wx.login({
success(res) {
// console.log(res);
_this.code = res.code
console.log(_this.code);
// 将code、encryptedData和iv作为参数交给SpringBoot去做解析
wx.request({
url:URL+'/api/add_phone',
method: 'get',
data:{
"code":_this.code,
"encryptedData":e.mp.detail.encryptedData,//注意 mpvue里面detail数据封装再e.mp下面,在原生的基础上又封装了一层。
"iv":e.mp.detail.iv
},
header: {'Content-Type': 'application/json'},
success: function(res) {
// 在控制台打印解析好的数据
console.log(res)
},
fail:function (res) {
// console.log(res);
}
})
}
})
},
三、后端实现数据解码 获取出用户手机号码
这里具体的springboot工程搭建我就不再列出来了 嘻嘻
1)准备工作
工程需要用到的maven依赖
<!-- 谷歌官方退出的Gson json解析工具 -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
<!-- 解码器-->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.46</version>
</dependency>
<!-- 发起http请求所需要的包 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.10</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
2)调用封装的解码工具类做解码
@GetMapping(value = "add_phone")
public ApiResponse addPhone(
@RequestParam(name = "code",required = true)
String code,
@RequestParam(name = "encryptedData",required = true)
String encryptedData,
@RequestParam(name = "iv",required = true)
String iv
) {
//从code中获取openId 和sessionKey。sessionKey是解码所需要的一个参数
OpenInfo openInfo = WechatDecryptDataUtil.getOpenId(code);
// 初始化json解析工具
JsonParser jsonParser = new JsonParser();
// openInfo不能为空 没有sessionKey 不能做解码
assert openInfo != null;
String result = WechatDecryptDataUtil.decryptData(
encryptedData,
openInfo.getSessionKey(),
iv
);
// 调用JsonObject解析返回的json数据
JsonObject obj = (JsonObject) jsonParser.parse(result);
// 赋值
MiniProUser miniProUser = new MiniProUser();
miniProUser.setOpenId(openInfo.getOpenId());
miniProUser.setCountryCode(obj.get("countryCode").toString().replace("\"", "").trim());
miniProUser.setPhoneNumber(obj.get("phoneNumber").toString().replace("\"", "").trim());
miniProUser.setTimestamp(String.valueOf(System.currentTimeMillis()));
// miniProUserService.addParkingUser(miniProUser);
// 这里的ApiResponse是一个Restful的封装 大家可以用自己定义的就好。
return ApiResponse.ofSuccess(200,"响应成功",miniProUser);
}
3)解析工具类
/**
* 微信工具类
*/
public class WechatDecryptDataUtil {
public static OpenInfo getOpenId(String code) {
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + Constant.APP_ID +
"&secret=" + Constant.APP_SECRET + "&js_code=" + code + "&grant_type=authorization_code";
HttpUtil httpUtil = new HttpUtil();
try {
// 以GET方式发起网络请求
HttpResult httpResult = httpUtil.doGet(url, null, null);
if(httpResult.getStatusCode() == 200) {
JsonParser jsonParser = new JsonParser();
JsonObject obj = (JsonObject) jsonParser.parse(httpResult.getBody());
if(obj.get("errcode") != null) {
return null;
} else {
OpenInfo openInfo = new OpenInfo();
openInfo.setOpenId(obj.get("openid").toString().replace("\"", "").trim());
openInfo.setSessionKey(obj.get("session_key").toString().replace("\"", "").trim());
return openInfo;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String getSession(String code) {
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + Constant.APP_ID +
"&secret=" + Constant.APP_SECRET + "&js_code=" + code + "&grant_type=authorization_code";
HttpUtil httpUtil = new HttpUtil();
try {
HttpResult httpResult = httpUtil.doGet(url, null, null);
if(httpResult.getStatusCode() == 200) {
JsonParser jsonParser = new JsonParser();
// System.out.println(httpResult.getBody());
JsonObject obj = (JsonObject) jsonParser.parse(httpResult.getBody());
// log.error("getOpenId: " + obj.toString());
if(obj.get("errcode") != null) {
// log.error("getOpenId returns errcode: " + obj.get("errcode"));
return "";
} else {
return obj.get("session_key").toString();
}
//return httpResult.getBody();
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public static String decryptData(String encryptDataB64, String sessionKeyB64, String ivB64) {
return new String(
decryptOfDiyIV(
Base64.decode(encryptDataB64),
Base64.decode(sessionKeyB64),
Base64.decode(ivB64)
)
);
}
private static final String KEY_ALGORITHM = "AES";
private static final String ALGORITHM_STR = "AES/CBC/PKCS7Padding";
private static Key key;
private static Cipher cipher;
private static void init(byte[] keyBytes) {
// 如果密钥不足16位,那么就补足. 这个if 中的内容很重要
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;
}
// 初始化
Security.addProvider(new BouncyCastleProvider());
// 转化成JAVA的密钥格式
key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
try {
// 初始化cipher
cipher = Cipher.getInstance(ALGORITHM_STR, "BC");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 解密方法
*
* @param encryptedData 要解密的字符串
* @param keyBytes 解密密钥
* @param ivs 自定义对称解密算法初始向量 iv
* @return 解密后的字节数组
*/
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;
}
}
4)附件
I MiniProUser封装
/**
* @author lyred
*/
@Data
@TableName(value = "mini_pro_user")
public class MiniProUser {
@TableId(type = IdType.AUTO)
private int id;
@TableField(value = "phone_number")
private String phoneNumber;
@TableField(value = "open_id")
private String openId;
@TableField(value = "country_code")
private String countryCode;
@TableField(value = "timestamp")
private String timestamp;
}
II OpenInfo 封装
@Data
public class OpenInfo {
private String openId;
private String sessionKey;
}
III 常量封装
public class Constant {
public static final String APP_ID = "appid";
public static final String APP_SECRET = "app_secret";
public static final String APP_KEY = "app_key";
}
IV 发起网络请求用到的工具类
public class HttpUtil {
// User-Agent
public static final String USERAGENT_FIREFOX = "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0";
public static final String USERAGENT_IE = "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko";
private CloseableHttpClient httpClient;
private BasicCookieStore cookieStore;
private HttpGet get;
private HttpPost post;
public static StringBuffer httpsRequest(String requestUrl, String requestMethod, String output) throws IOException {
URL url = new URL(requestUrl);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setRequestMethod(requestMethod);
if (null != output) {
OutputStream outputStream = connection.getOutputStream();
outputStream.write(output.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
connection.disconnect();
return buffer;
}
public HttpResult doGet(String url, Map<String, String> headers, Map<String, String> params) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, ClientProtocolException, IOException {
if (url == null|| url.equals("")) {
return null;
}
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
cookieStore = new BasicCookieStore();
CloseableHttpClient httpclient = HttpClients.custom().setDefaultCookieStore(cookieStore)
.setSSLSocketFactory(sslsf).build();
HttpResult result = null;
try {
url = url + "?" + parseParams(params);
HttpGet httpget = new HttpGet(url);
httpget.setHeaders(parseHeader(headers));
CloseableHttpResponse response = httpclient.execute(httpget);
try {
HttpEntity entity = response.getEntity();
if (entity != null) {
result = new HttpResult();
result.setCookies(cookieStore.getCookies());
result.setStatusCode(response.getStatusLine().getStatusCode());
result.setHeaders(response.getAllHeaders());
result.setBody(EntityUtils.toString(entity));
}
} finally {
response.close();
}
} finally {
httpclient.close();
}
return result;
}
public HttpResult doPost(String url, Map<String, String> headers, Map<String, String> postData, String encoding) throws Exception {
if (url == null|| url.equals("")) {
return null;
}
if (encoding == null|| encoding.equals("")) {
encoding = "utf-8";
}
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
cookieStore = new BasicCookieStore();
CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore)
.setSSLSocketFactory(sslsf).build();
post = new HttpPost(url);
List<NameValuePair> list = new ArrayList<NameValuePair>();
for (String tmp : postData.keySet()) {
list.add(new BasicNameValuePair(tmp, postData.get(tmp)));
}
post.setEntity(new UrlEncodedFormEntity(list, encoding));
post.setHeaders(parseHeader(headers));
CloseableHttpResponse response = httpClient.execute(post);
HttpEntity entity = response.getEntity();
HttpResult result = new HttpResult();
result.setCookies(cookieStore.getCookies());
result.setStatusCode(response.getStatusLine().getStatusCode());
result.setHeaders(response.getAllHeaders());
result.setBody(EntityUtils.toString(entity, encoding));
close(entity, response);
return result;
}
private String parseParams(Map<String, String> params) {
if (params == null || params.isEmpty()) {
return "";
}
StringBuffer sb = new StringBuffer();
for (String key : params.keySet()) {
sb.append(key + "=" + params.get(key) + "&");
}
return sb.substring(0, sb.length() - 1);
}
private Header[] parseHeader(Map<String, String> headers) {
if (headers == null || headers.isEmpty()) {
return getDefaultHeaders();
}
Header[] retHeader = new BasicHeader[headers.size()];
int i = 0;
for (String str : headers.keySet()) {
retHeader[i++] = new BasicHeader(str, headers.get(str));
}
return retHeader;
}
private Header[] getDefaultHeaders() {
Header[] headers = new BasicHeader[3];
headers[0] = new BasicHeader("User-Agent", USERAGENT_IE);
headers[1] = new BasicHeader("Accept-Encoding", "gzip, deflate");
headers[2] = new BasicHeader("Accept-Language", "en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3");
return headers;
}
private void close(HttpEntity entity, CloseableHttpResponse response) {
try {
if (entity != null) {
InputStream input = entity.getContent();
input.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
//e.printStackTrace();
}
}
}
/**
* 下载文件
* @param url 下载文件的链接
* @param destFile 包含路径的目标文件名
* @param headers 请求头
* @return
*/
public HttpResult downloadFile(String url, String destFile, Map<String, String> headers) throws Exception {
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
BasicCookieStore cookieStore = new BasicCookieStore();
CloseableHttpClient httpclient = HttpClients.custom().setDefaultCookieStore(cookieStore).setSSLSocketFactory(sslsf).build();
HttpGet get = new HttpGet(url);
get.setHeaders(parseHeader(headers));
InputStream input = null;
CloseableHttpResponse response = null;
HttpResult result = null;
try {
response = httpclient.execute(get);
HttpEntity entity = response.getEntity();
input = entity.getContent();
File file = new File(destFile);
FileOutputStream fos = new FileOutputStream(file);
int len = -1;
byte[] tmp = new byte[1024];
while((len=input.read(tmp)) != -1) {
fos.write(tmp, 0, len);
}
fos.flush();
fos.close();
result = new HttpResult();
result.setCookies(cookieStore.getCookies());
result.setStatusCode(response.getStatusLine().getStatusCode());
result.setHeaders(response.getAllHeaders());
result.setBody(EntityUtils.toString(entity, Consts.UTF_8));
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(input != null) {
input.close();
}
if(response != null) {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
}
V 网络请求结果的分装
public class HttpResult {
private List<Cookie> cookies;
private HashMap<String, Header> headers;
private int statusCode;
private String body;
public List<Cookie> getCookies() {
return cookies;
}
public void setCookies(List<Cookie> cookies) {
this.cookies = cookies;
}
public HashMap<String, Header> getHeaders() {
return headers;
}
public void setHeaders(Header[] headerAll) {
headers = new HashMap<String, Header>();
for (Header header : headerAll) {
headers.put(header.getName(), header);
}
}
public int getStatusCode() {
return statusCode;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("======================= HttpResult toString start ========================\n");
sb.append("----- statusCode: " + statusCode + "\n");
if(headers != null) {
sb.append("----- headers:\n");
for(String key : headers.keySet()) {
sb.append("\t" + key + " : " + headers.get(key) + "\n");
}
}
if(cookies != null) {
sb.append("----- cookies:\n");
for(Cookie cookie : cookies) {
sb.append("\t" + cookie.getName() + " : " + cookie.getValue() + "\n");
}
}
sb.append("======================= body start ========================\n");
sb.append(body);
sb.append("======================= body end ========================\n");
sb.append("======================= HttpResult toString end =======================");
return sb.toString();
}
public String getCookieValue(String cookieName) {
if(cookies.isEmpty()) {
return null;
}
for(Cookie cookie : cookies) {
if(cookie.getName().equals(cookieName)) {
return cookie.getValue();
}
}
return null;
}
}