From 5a72f70da19302b4c408ada8618f2ff4e1df6a76 Mon Sep 17 00:00:00 2001 From: zhizhi wu <2377881365@qq.com> Date: Fri, 3 Dec 2021 14:50:32 +0800 Subject: [PATCH] =?UTF-8?q?=E8=85=BE=E8=AE=AF=E7=89=A9=E8=81=94=E7=BD=91?= =?UTF-8?q?=20=E5=BE=AE=E4=BF=A1=E7=94=A8=E6=88=B7=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../signin/api/FiotExplorerController.java | 10 +- .../com/ccsens/signin/bean/vo/FiotVo.java | 1 + signin/src/main/resources/application.yml | 4 +- .../com/ccsens/util/KCPlayerSignature.java | 2 +- .../com/ccsens/util/RestTemplateUtil.java | 32 ++++ .../bean/po/wxfiotexplorer/FiotSignin.java | 13 +- .../po/wxfiotexplorer/FiotSigninResponse.java | 3 + .../bean/po/wxfiotexplorer/ResponseInfo.java | 4 +- .../com/ccsens/wechatutil/util/TC3Util.java | 137 ++++++++++++++---- .../FiotExplorerSigninUtil.java | 26 ++-- wechatutil/src/main/resources/application.yml | 4 +- 11 files changed, 183 insertions(+), 53 deletions(-) diff --git a/signin/src/main/java/com/ccsens/signin/api/FiotExplorerController.java b/signin/src/main/java/com/ccsens/signin/api/FiotExplorerController.java index 2b1c0c67..76effe8f 100644 --- a/signin/src/main/java/com/ccsens/signin/api/FiotExplorerController.java +++ b/signin/src/main/java/com/ccsens/signin/api/FiotExplorerController.java @@ -12,6 +12,7 @@ import com.ccsens.signin.exception.UserLoginException; import com.ccsens.util.JsonResponse; import com.ccsens.util.WebConstant; import com.ccsens.util.wx.WxXcxUtil; +import com.ccsens.wechatutil.bean.po.wxfiotexplorer.FiotSigninResponse; import com.ccsens.wechatutil.wxfiotexplorer.FiotExplorerSigninUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParams; @@ -45,12 +46,13 @@ public class FiotExplorerController { public JsonResponse userSignin(@ApiParam @Validated @RequestBody(required = true)FiotDto.Signin signin) throws Exception { log.info("物联网用户登录:{}", signin); String type = "FIOT"; - WxXcxUtil.WechatUser wechatUser = WxXcxUtil.getUserInfo(signin.getCode(), type); - String token = FiotExplorerSigninUtil.getToken(wechatUser.openid, signin.getNickName(), signin.getAvatar(), WxXcxUtil.appId(type)); + WxXcxUtil.WechatUser wechatUser = WxXcxUtil.getUserInfo(signin.getCode(), "yanyuan"); + log.info("用户账号:{}", wechatUser); + FiotSigninResponse response = FiotExplorerSigninUtil.getToken(wechatUser.openid, signin.getNickName(), signin.getAvatar(), WxXcxUtil.appId(type)); FiotVo.Signin vo = new FiotVo.Signin(); - vo.setToken(token); + vo.setToken(response.getToken()); + vo.setExpireAt(response.getExpireAt()); log.info("物联网用户登录结果:{}", vo); return JsonResponse.newInstance().ok(vo); - } } diff --git a/signin/src/main/java/com/ccsens/signin/bean/vo/FiotVo.java b/signin/src/main/java/com/ccsens/signin/bean/vo/FiotVo.java index 9cc85766..6cc79652 100644 --- a/signin/src/main/java/com/ccsens/signin/bean/vo/FiotVo.java +++ b/signin/src/main/java/com/ccsens/signin/bean/vo/FiotVo.java @@ -14,5 +14,6 @@ public class FiotVo { @ApiModel("物联网登录-返回") public static class Signin{ private String token; + private long expireAt; } } diff --git a/signin/src/main/resources/application.yml b/signin/src/main/resources/application.yml index e75cc2c3..ebc544af 100644 --- a/signin/src/main/resources/application.yml +++ b/signin/src/main/resources/application.yml @@ -1,5 +1,5 @@ spring: profiles: - active: prod - include: util-prod,common + active: test + include: util-test,common diff --git a/util/src/main/java/com/ccsens/util/KCPlayerSignature.java b/util/src/main/java/com/ccsens/util/KCPlayerSignature.java index c0967ee8..f6bf029d 100644 --- a/util/src/main/java/com/ccsens/util/KCPlayerSignature.java +++ b/util/src/main/java/com/ccsens/util/KCPlayerSignature.java @@ -59,7 +59,7 @@ public class KCPlayerSignature{ return strSign; } - private String base64Encode(byte[] buffer) { + public static String base64Encode(byte[] buffer) { Base64.Encoder encoder = Base64.getEncoder(); return encoder.encodeToString(buffer); } diff --git a/util/src/main/java/com/ccsens/util/RestTemplateUtil.java b/util/src/main/java/com/ccsens/util/RestTemplateUtil.java index dd840609..c9766256 100644 --- a/util/src/main/java/com/ccsens/util/RestTemplateUtil.java +++ b/util/src/main/java/com/ccsens/util/RestTemplateUtil.java @@ -1,5 +1,6 @@ package com.ccsens.util; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; @@ -87,6 +88,37 @@ public class RestTemplateUtil { return response.getBody(); } + public static String postBodySpecialHeader(String url, Object params, Map headMap) { + log.info("路径:{}, 参数:{}", url, params); + HttpHeaders httpHeaders = new HttpHeaders(); + MediaType type=MediaType.parseMediaType("application/json;charset=UTF-8"); + httpHeaders.setContentType(type); + if (CollectionUtil.isNotEmpty(headMap)) { + for (Map.Entry entry: headMap.entrySet()) { + httpHeaders.set(entry.getKey(), entry.getValue()); + } + } + +// MultiValueMap map=new LinkedMultiValueMap<>(); + + JSONObject json = JSON.parseObject(JSON.toJSONString(params)); + HttpEntity> objectHttpEntity = new HttpEntity<>(json,httpHeaders); + URI uri = null; + try { + uri = new URI(url); + }catch (URISyntaxException e) { + log.error("转换路径异常:{}", e); + throw new BaseException(CodeEnum.URL_ERROR); + } + log.info("uri:{}",uri); + log.info("json:{}",json); + log.info("objectHttpEntity:{}",objectHttpEntity); + + ResponseEntity response = util.restTemplate.postForEntity(uri, objectHttpEntity, String.class); + log.info("返回:{}", response); + return response.getBody(); + } + public static String postBody1(String url, List params) { log.info("路径:{}, 参数:{}", url, params); HttpHeaders httpHeaders = new HttpHeaders(); diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/wxfiotexplorer/FiotSignin.java b/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/wxfiotexplorer/FiotSignin.java index fa209c7e..d8d556c5 100644 --- a/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/wxfiotexplorer/FiotSignin.java +++ b/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/wxfiotexplorer/FiotSignin.java @@ -5,6 +5,7 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.HexUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; import com.ccsens.wechatutil.util.TC3Util; import lombok.Data; @@ -23,38 +24,47 @@ public class FiotSignin { /** * 公共参数,本接口取值:AppGetTokenByWeiXin */ + @JSONField(name="Action") private String Action = "AppGetTokenByWeiXin"; /** * 公共参数,唯一请求 ID,可自行生成,推荐使用 uuid。定位问题时,需提供该次请求的 RequestId */ + @JSONField(name="RequestId") private String RequestId = UUID.randomUUID().toString(); /** * 公共参数,应用 AppKey ,用于标识对应的小程序或 App */ + @JSONField(name="AppKey") private String AppKey = null; /** * 公共参数,请求签名,需用户自行生成,用于校验请求的合法性 */ + @JSONField(name="Signature") private String Signature = null; /** * 公共参数,请求的 UINX 时间戳(秒级) */ + @JSONField(name="Timestamp") private long Timestamp = System.currentTimeMillis() / 1000; /** * 公共参数,随机正整数,与 Timestamp 联合起来,防止重放攻击 */ + @JSONField(name="Nonce") private int Nonce = new Random().nextInt(10000); /** * 微信用户的 OpenID 或 UnionID */ + @JSONField(name="WxOpenID") private String WxOpenID; /** * 昵称 */ + @JSONField(name="NickName") private String NickName; /** * 头像 */ + @JSONField(name="Avatar") private String Avatar; public FiotSignin() { @@ -66,7 +76,8 @@ public class FiotSignin { this.NickName = nickName; this.Avatar = avatar; this.AppKey = appKey; - this.Signature = TC3Util.generateSignature("iot", "iot.cloud.tencent.com", this.Timestamp, null); + JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(this)); + this.Signature = TC3Util.generateSignature(json); } diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/wxfiotexplorer/FiotSigninResponse.java b/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/wxfiotexplorer/FiotSigninResponse.java index 896e4286..98452ccf 100644 --- a/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/wxfiotexplorer/FiotSigninResponse.java +++ b/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/wxfiotexplorer/FiotSigninResponse.java @@ -1,5 +1,6 @@ package com.ccsens.wechatutil.bean.po.wxfiotexplorer; +import com.alibaba.fastjson.annotation.JSONField; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -11,7 +12,9 @@ import lombok.Data; @Data public class FiotSigninResponse { @ApiModelProperty("截止时间,UINX 秒级时间戳") + @JSONField(name = "ExpireAt") private Long ExpireAt; @ApiModelProperty("开发平台返回的 AccessToken,通过该 Token 进行登录后的接口请求") + @JSONField(name = "Token") private String Token; } diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/wxfiotexplorer/ResponseInfo.java b/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/wxfiotexplorer/ResponseInfo.java index 4aa5486d..b4ff8c63 100644 --- a/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/wxfiotexplorer/ResponseInfo.java +++ b/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/wxfiotexplorer/ResponseInfo.java @@ -10,7 +10,9 @@ import lombok.Data; */ @Data public class ResponseInfo { - private Info Response; + private int code; + private String msg; + private Info data; private String RequestId; diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/util/TC3Util.java b/wechatutil/src/main/java/com/ccsens/wechatutil/util/TC3Util.java index f5b3be29..cd52b272 100644 --- a/wechatutil/src/main/java/com/ccsens/wechatutil/util/TC3Util.java +++ b/wechatutil/src/main/java/com/ccsens/wechatutil/util/TC3Util.java @@ -1,6 +1,9 @@ package com.ccsens.wechatutil.util; +import cn.hutool.core.codec.Base64Encoder; import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.ccsens.util.KCPlayerSignature; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; @@ -9,9 +12,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; -import java.util.TreeMap; +import java.util.*; /** * @description: @@ -22,7 +23,12 @@ public class TC3Util { private final static Charset UTF8 = StandardCharsets.UTF_8; private final static String SECRET_ID = "AKIDxhBRRAdplRpwnMfnfGaeRxDBsJTN0NTI"; private final static String SECRET_KEY = "Zrte9MPFo68tMZU8WcXDeqnVx95rYzA6"; + private final static String APP_KEY = "mEulfDBBOFeOjGavy"; + private final static String APP_SECRET = "FaFKWiwVUWbJmfxVnSdd"; private final static String CT_JSON = "application/json; charset=utf-8"; + //签名算法 + private static final String HMAC_ALGORITHM = "HmacSHA1"; + private static final String CONTENT_CHARSET = "UTF-8"; public static byte[] hmac256(byte[] key, String msg) throws Exception { Mac mac = Mac.getInstance("HmacSHA256"); @@ -37,6 +43,72 @@ public class TC3Util { return DatatypeConverter.printHexBinary(d).toLowerCase(); } + public static Map getHeaders(String service, long timestamp, String signature){ + Map headMap = new HashMap<>(); + String algorithm = "TC3-HMAC-SHA256"; + String signedHeaders = "content-type;host"; + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + // 注意时区,否则容易出错 + sdf.setTimeZone(TimeZone.getTimeZone("UTC")); + String date = sdf.format(new Date(Long.valueOf(timestamp + "000"))); + String credentialScope = date + "/" + service + "/" + "tc3_request"; + String authorization = algorithm + " " + "Credential=" + SECRET_ID + "/" + credentialScope + ", " + + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature; + headMap.put("Authorization", authorization); + return headMap; + } + + public static void main(String[] args) throws Exception { + JSONObject json = new JSONObject(); + json.put("Action","AppGetTokenByWeiXin"); + json.put("RequestId","4c582f20-608a-41eb-8a04-b19cd341a328"); + json.put("AppKey","mEulfDBBOFeOjGavy"); + json.put("Timestamp","1638345578"); + json.put("Nonce","3493"); + json.put("WxOpenId","oOBSe5HAi885IlNeAAb3FQYxwExI"); + json.put("NickName","wu"); + json.put("Avatar","https://thirdwx.qlogo.cn/mmopen/vi_32/4KIkPtTLnuGdQPo1YqiaqRAgjyIPz4NyDzZVwwKJiatibWhszIH02XmWyqnl7LW1zYmRMbF2UYQG5o4N0cgyPH0qw/132"); + System.out.println(json); + String s = generateSignature(json); + System.out.println("s:" + s); +// String data = "Action=AppCreateCellphoneUser&AppKey=ahPxdK****TGrejd&CountryCode=86&Nonce=71087795&Password=My!P@ssword&PhoneNumber=13900000000&RequestId=8b8d499bbba1ac28b6da21b4&Timestamp=1546315200&VerificationCode=123456"; +// Mac mac = Mac.getInstance(HMAC_ALGORITHM); +// SecretKeySpec secretKey = new SecretKeySpec("NcbHqk****TCGbKnQH".getBytes(), HMAC_ALGORITHM); +// mac.init(secretKey); +// +// byte[] hash = mac.doFinal(data.getBytes()); +// String strSign = Base64Encoder.encode(hash); +// System.out.println("strSign:" + strSign); + } + + public static String generateSignature(Map param) throws Exception { + StringBuilder builder = new StringBuilder(); + Set keys = param.keySet(); + Object[] keyArr = keys.toArray(); + + Arrays.sort(keyArr); + for (Object keyObj: keyArr) { + String key = (String) keyObj; + if (param.get(key) == null || "".equals(param.get(key))) { + continue; + } + builder.append(key.replaceAll("_",".")).append("=").append(param.get(key)).append("&"); + } + System.out.println("builder:" + builder.toString()); + String plaintext = builder.substring(0, builder.length() - 1); + + + + Mac mac = Mac.getInstance(HMAC_ALGORITHM); + SecretKeySpec secretKey = new SecretKeySpec(APP_SECRET.getBytes(), HMAC_ALGORITHM); + mac.init(secretKey); + + byte[] hash = mac.doFinal(plaintext.getBytes()); +// String strSign = KCPlayerSignature.base64Encode(hash); + String strSign = Base64Encoder.encode(hash); +// strSign = strSign.replace(" ", "").replace("\n", "").replace("\r", ""); + return strSign; + } public static String generateSignature(String service, String host, long timestamp, String payload) throws Exception { //String service = "cvm"; //String host = "cvm.tencentcloudapi.com"; @@ -74,34 +146,35 @@ public class TC3Util { byte[] secretService = hmac256(secretDate, service); byte[] secretSigning = hmac256(secretService, "tc3_request"); String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase(); - System.out.println(signature); - - // ************* 步骤 4:拼接 Authorization ************* - String authorization = algorithm + " " + "Credential=" + SECRET_ID + "/" + credentialScope + ", " - + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature; - - TreeMap headers = new TreeMap(); - headers.put("Authorization", authorization); - headers.put("Content-Type", CT_JSON); - headers.put("Host", host); -// headers.put("X-TC-Action", action); -// headers.put("X-TC-Timestamp", timestamp); -// headers.put("X-TC-Version", version); -// headers.put("X-TC-Region", region); - - StringBuilder sb = new StringBuilder(); - sb.append("curl -X POST https://").append(host) - .append(" -H \"Authorization: ").append(authorization).append("\"") - .append(" -H \"Content-Type: application/json; charset=utf-8\"") - .append(" -H \"Host: ").append(host).append("\""); -// .append(" -H \"X-TC-Action: ").append(action).append("\"") -// .append(" -H \"X-TC-Timestamp: ").append(timestamp).append("\"") -// .append(" -H \"X-TC-Version: ").append(version).append("\"") -// .append(" -H \"X-TC-Region: ").append(region).append("\"") - if (StrUtil.isNotEmpty(payload)) { - sb.append(" -d '").append(payload).append("'"); - } - - return sb.toString(); + return signature; +// System.out.println(signature); +// +// // ************* 步骤 4:拼接 Authorization ************* +// String authorization = algorithm + " " + "Credential=" + SECRET_ID + "/" + credentialScope + ", " +// + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature; +// +// TreeMap headers = new TreeMap(); +// headers.put("Authorization", authorization); +// headers.put("Content-Type", CT_JSON); +// headers.put("Host", host); +//// headers.put("X-TC-Action", action); +//// headers.put("X-TC-Timestamp", timestamp); +//// headers.put("X-TC-Version", version); +//// headers.put("X-TC-Region", region); +// +// StringBuilder sb = new StringBuilder(); +// sb.append("curl -X POST https://").append(host) +// .append(" -H \"Authorization: ").append(authorization).append("\"") +// .append(" -H \"Content-Type: application/json; charset=utf-8\"") +// .append(" -H \"Host: ").append(host).append("\""); +//// .append(" -H \"X-TC-Action: ").append(action).append("\"") +//// .append(" -H \"X-TC-Timestamp: ").append(timestamp).append("\"") +//// .append(" -H \"X-TC-Version: ").append(version).append("\"") +//// .append(" -H \"X-TC-Region: ").append(region).append("\"") +// if (StrUtil.isNotEmpty(payload)) { +// sb.append(" -d '").append(payload).append("'"); +// } +// +// return sb.toString(); } } diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/wxfiotexplorer/FiotExplorerSigninUtil.java b/wechatutil/src/main/java/com/ccsens/wechatutil/wxfiotexplorer/FiotExplorerSigninUtil.java index 65bc60e1..fb437233 100644 --- a/wechatutil/src/main/java/com/ccsens/wechatutil/wxfiotexplorer/FiotExplorerSigninUtil.java +++ b/wechatutil/src/main/java/com/ccsens/wechatutil/wxfiotexplorer/FiotExplorerSigninUtil.java @@ -9,6 +9,7 @@ import com.ccsens.util.exception.BaseException; import com.ccsens.wechatutil.bean.po.wxfiotexplorer.FiotSignin; import com.ccsens.wechatutil.bean.po.wxfiotexplorer.FiotSigninResponse; import com.ccsens.wechatutil.bean.po.wxfiotexplorer.ResponseInfo; +import com.ccsens.wechatutil.util.TC3Util; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -46,13 +47,13 @@ public class FiotExplorerSigninUtil { - public static String getToken(String openId, String nickName, String avatar, String appKey) throws Exception { + public static FiotSigninResponse getToken(String openId, String nickName, String avatar, String appKey) throws Exception { log.info("物联网查询token:{},{},{}", openId, nickName, avatar); String key = StrUtil.format(TOKEN_KEY, openId); Object o = util.redisUtil.get(key); log.info("{}缓存的token:{}", key, o); if (o != null) { - return (String) o; + return (FiotSigninResponse) o; } // 查询token @@ -61,17 +62,22 @@ public class FiotExplorerSigninUtil { String s = RestTemplateUtil.postBody(SIGN_URL, fiotSignin); log.info("登录结果:{}", s); if (StrUtil.isEmpty(s)) { + log.info("登录结果为空"); throw new BaseException(CodeError.THIRD_ERROR); } - ResponseInfo res = JSONObject.parseObject(s, ResponseInfo.class); - if (res.getResponse() == null) { - throw new BaseException(CodeError.THIRD_ERROR); - } else if (res.getResponse().getError() != null ) { - throw new BaseException(CodeError.THIRD_ERROR.getCode(), res.getResponse().getError().getMessage()); + JSONObject json = JSONObject.parseObject(s); + log.info("json:{}", json); + String dataKey = "data"; + String realDataKey = "Data"; + if (json.get(dataKey) == null || json.getJSONObject(dataKey).get(realDataKey) == null) { + log.info("数据异常"); + throw new BaseException(CodeError.THIRD_ERROR.getCode(), json.getString("msg")); } - FiotSigninResponse data = res.getResponse().getData(); - util.redisUtil.set(key, data.getToken(), data.getExpireAt() - System.currentTimeMillis()/1000); - return data.getToken(); + + FiotSigninResponse data = JSONObject.parseObject(json.getJSONObject(dataKey).getString(realDataKey), FiotSigninResponse.class); + util.redisUtil.set(key, data, data.getExpireAt() - System.currentTimeMillis()/1000); + log.info("登录返回:{}", data); + return data; } diff --git a/wechatutil/src/main/resources/application.yml b/wechatutil/src/main/resources/application.yml index b5408a3a..ebc544af 100644 --- a/wechatutil/src/main/resources/application.yml +++ b/wechatutil/src/main/resources/application.yml @@ -1,5 +1,5 @@ spring: profiles: - active: dev - include: util-dev,common + active: test + include: util-test,common