|
|
@@ -1,9 +1,12 @@
|
|
|
package bus.controller.biz;
|
|
|
|
|
|
import bus.model.dto.req.WxLoginReq;
|
|
|
+import bus.model.vo.WXDecrypt;
|
|
|
+import bus.model.vo.WxEncryptedData;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import cn.hutool.http.HttpUtil;
|
|
|
import cn.hutool.json.JSONObject;
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
import com.github.pagehelper.PageHelper;
|
|
|
import com.github.pagehelper.PageSerializable;
|
|
|
@@ -18,14 +21,21 @@ import com.sun.jndi.toolkit.url.UrlUtil;
|
|
|
import io.swagger.annotations.Api;
|
|
|
import io.swagger.annotations.ApiOperation;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.codec.binary.Base64;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.data.redis.core.StringRedisTemplate;
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
import com.qzwisdom.qzframework.core.tool.base.controller.BaseController;
|
|
|
|
|
|
+import javax.crypto.Cipher;
|
|
|
+import javax.crypto.spec.IvParameterSpec;
|
|
|
+import javax.crypto.spec.SecretKeySpec;
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
+import java.security.AlgorithmParameters;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.Map;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
|
/**
|
|
|
@@ -51,6 +61,43 @@ public class WChatUserController implements BaseController {
|
|
|
|
|
|
private static final String ERROR_CODE_STR = "errcode";
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private StringRedisTemplate stringRedisTemplate;
|
|
|
+
|
|
|
+ private static final String WX_ACCESS_TOKEN_KEY = "wx:access_token";
|
|
|
+ // access_token 有效期为 7200 秒,我们设置缓存时间为 7000 秒,留出一些余量
|
|
|
+ private static final long ACCESS_TOKEN_EXPIRE = 7000L;
|
|
|
+
|
|
|
+ private String getAccessToken() {
|
|
|
+ // 先从Redis获取
|
|
|
+ String accessToken = stringRedisTemplate.opsForValue().get(WX_ACCESS_TOKEN_KEY);
|
|
|
+ if (StrUtil.isNotBlank(accessToken)) {
|
|
|
+ return accessToken;
|
|
|
+ }
|
|
|
+ // Redis中不存在,则从微信服务器获取
|
|
|
+ String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token" +
|
|
|
+ "?grant_type=client_credential" +
|
|
|
+ "&appid=" + appId +
|
|
|
+ "&secret=" + appSecret;
|
|
|
+
|
|
|
+ String tokenJson = HttpUtil.get(accessTokenUrl, TIME_OUT);
|
|
|
+ JSONObject tokenObj = new JSONObject(tokenJson);
|
|
|
+ if (tokenObj.get(ERROR_CODE_STR) != null && tokenObj.get(ERROR_CODE_STR, Integer.class) != 0) {
|
|
|
+ throw new BusinessException("获取access_token失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取新的access_token
|
|
|
+ accessToken = tokenObj.getStr("access_token");
|
|
|
+ // 存入Redis并设置过期时间
|
|
|
+ stringRedisTemplate.opsForValue().set(
|
|
|
+ WX_ACCESS_TOKEN_KEY,
|
|
|
+ accessToken,
|
|
|
+ ACCESS_TOKEN_EXPIRE,
|
|
|
+ TimeUnit.SECONDS
|
|
|
+ );
|
|
|
+ return accessToken;
|
|
|
+ }
|
|
|
+
|
|
|
@RequestMapping(value = "/auto/login", method = RequestMethod.POST)
|
|
|
@ApiOperation(value = "小程序登陆调用")
|
|
|
public SsoUserAuthDto wxLogin(HttpServletRequest request, HttpServletResponse response,
|
|
|
@@ -88,7 +135,49 @@ public class WChatUserController implements BaseController {
|
|
|
return map;
|
|
|
}
|
|
|
|
|
|
+ @RequestMapping(value = "/getPhoneNumber", method = RequestMethod.POST)
|
|
|
+ @ApiOperation(value = "新板本-获取微信小程序手机号")
|
|
|
+ public String getPhoneNumber(@RequestParam(required = true) String code) {
|
|
|
+ if (StrUtil.isBlank(code)) {
|
|
|
+ throw new BusinessException("code不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ String accessToken = getAccessToken();
|
|
|
+ String phoneUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber" +
|
|
|
+ "?access_token=" + accessToken;
|
|
|
|
|
|
+ Map<String, Object> paramMap = new HashMap<>();
|
|
|
+ paramMap.put("code", code);
|
|
|
+ String phoneJson = HttpUtil.post(phoneUrl, JSON.toJSONString(paramMap));
|
|
|
+
|
|
|
+ JSONObject phoneObj = new JSONObject(phoneJson);
|
|
|
+ if (phoneObj.get(ERROR_CODE_STR) != null && phoneObj.get(ERROR_CODE_STR, Integer.class) != 0) {
|
|
|
+ throw new BusinessException("获取手机号失败");
|
|
|
+ }
|
|
|
+ return phoneJson;
|
|
|
+ }
|
|
|
+
|
|
|
+ @ApiOperation(value = "老板本-解密获取手机号")
|
|
|
+ @RequestMapping(value = "/encryptedData", method = RequestMethod.POST)
|
|
|
+ @ResponseBody
|
|
|
+ public WXDecrypt encryptedData(@RequestBody WxEncryptedData wxEncryptedData) throws Exception {
|
|
|
+ // 第一个,加密数据串(String);
|
|
|
+ // 第二个,session_key需要通过微信小程序的code获得(String);
|
|
|
+ // 第三个,数据加密时所使用的偏移量,解密时需要使用(String);第四个,编码
|
|
|
+ String encryptedData = wxEncryptedData.getEncryptedData();
|
|
|
+ String sessionKey = wxEncryptedData.getSessionKey();
|
|
|
+ String iv = wxEncryptedData.getIv();
|
|
|
+
|
|
|
+ String result = decrypt(encryptedData, sessionKey, iv, "UTF-8");
|
|
|
+
|
|
|
+ if (null != result && result.length() > 0) {
|
|
|
+ // 将解密后的JSON格式字符串转化为对象
|
|
|
+ WXDecrypt wxDecrypt = JSONUtil.toBean(result, WXDecrypt.class);
|
|
|
+ return wxDecrypt;
|
|
|
+ } else {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* 详情
|
|
|
@@ -127,4 +216,38 @@ public class WChatUserController implements BaseController {
|
|
|
// return "删除成功";
|
|
|
// }
|
|
|
|
|
|
+ /**
|
|
|
+ * 解密
|
|
|
+ * @param data
|
|
|
+ * @param key
|
|
|
+ * @param iv
|
|
|
+ * @param encodingFormat
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public static String decrypt(String data, String key, String iv, String encodingFormat) throws Exception {
|
|
|
+ // 被加密的数据
|
|
|
+ byte[] dataByte = Base64.decodeBase64(data);
|
|
|
+ // 加密秘钥
|
|
|
+ byte[] keyByte = Base64.decodeBase64(key);
|
|
|
+ // 偏移量
|
|
|
+ byte[] ivByte = Base64.decodeBase64(iv);
|
|
|
+ try {
|
|
|
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
|
|
|
+ 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, encodingFormat);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
}
|