From 9957cd70a4152cf8ddb695a360466dd529ec2de3 Mon Sep 17 00:00:00 2001 From: "udf_admin@163.com" Date: Mon, 29 Jan 2018 23:31:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BE=AE=E4=BF=A1MP=E7=9A=84?= =?UTF-8?q?=E9=9B=86=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/itkk/udf/weixin/mp/api/Oauth2.java | 142 ++++++++++++++++++ .../weixin/mp/api/WeixinMpApiProperties.java | 5 + .../udf/weixin/mp/api}/WeixinMpConsont.java | 23 ++- .../udf/weixin/mp/api}/WeixinMpException.java | 2 +- .../udf/weixin/mp/api/domain/BaseResult.java | 32 ++++ .../udf/weixin/mp/api/domain/Oauth2Token.java | 51 +++++++ .../weixin/mp/api/domain/Oauth2UserInfo.java | 77 ++++++++++ .../mp/service/WeixinMpCallbackService.java | 5 +- 8 files changed, 332 insertions(+), 5 deletions(-) create mode 100644 udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/Oauth2.java rename {udf-starter-weixin-mp/src/main/java/org/itkk/udf/weixin/mp => udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api}/WeixinMpConsont.java (73%) rename {udf-starter-weixin-mp/src/main/java/org/itkk/udf/weixin/mp => udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api}/WeixinMpException.java (96%) create mode 100644 udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/domain/BaseResult.java create mode 100644 udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/domain/Oauth2Token.java create mode 100644 udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/domain/Oauth2UserInfo.java diff --git a/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/Oauth2.java b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/Oauth2.java new file mode 100644 index 0000000..b9e27e3 --- /dev/null +++ b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/Oauth2.java @@ -0,0 +1,142 @@ +package org.itkk.udf.weixin.mp.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.itkk.udf.weixin.mp.api.domain.BaseResult; +import org.itkk.udf.weixin.mp.api.domain.Oauth2Token; +import org.itkk.udf.weixin.mp.api.domain.Oauth2UserInfo; +import org.itkk.udf.weixin.mp.api.meta.WeixinMpApiAuthMeta; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.io.IOException; + +/** + * Oauth2 + */ +@Component +public class Oauth2 { + + /** + * weixinMpApiProperties + */ + @Autowired + private WeixinMpApiProperties weixinMpApiProperties; + + /** + * externalRestTemplate + */ + @Autowired + @Qualifier("externalRestTemplate") + private RestTemplate externalRestTemplate; + + /** + * objectMapper + */ + @Autowired + private ObjectMapper objectMapper; + + /** + * 通过code换取网页授权access_token + * + * @param businessCode 业务代码(关联appid等信息) + * @param code 填写第一步获取的code参数 + * @return Oauth2Token + * @throws IOException IOException + */ + public Oauth2Token accessToken(String businessCode, String code) throws IOException { + //获得认证相关信息 + WeixinMpApiAuthMeta auth = weixinMpApiProperties.getAuth().get(businessCode); + //获得接口地址 + String path = weixinMpApiProperties.getSnsPath().get("sns_oauth2_access_token"); + //拼接url + StringBuilder url = new StringBuilder(path); + url.append("?appid=").append(auth.getAppId()).append("&secret=").append(auth.getAppSecret()).append("&code=").append(code).append("&grant_type=authorization_code"); + //请求 + ResponseEntity result = externalRestTemplate.getForEntity(url.toString(), String.class); + //解析结果 + Oauth2Token token = objectMapper.readValue(result.getBody(), Oauth2Token.class); + //验证 + WeixinMpConsont.checkResult(token); + //返回 + return token; + } + + /** + * 刷新access_token(如果需要) + * + * @param businessCode 业务代码(关联appid等信息) + * @param refreshToken 填写为refresh_token + * @return Oauth2Token + * @throws IOException IOException + */ + public Oauth2Token refreshToken(String businessCode, String refreshToken) throws IOException { + //获得认证相关信息 + WeixinMpApiAuthMeta auth = weixinMpApiProperties.getAuth().get(businessCode); + //获得接口地址 + String path = weixinMpApiProperties.getSnsPath().get("sns_oauth2_refresh_token"); + //拼接url + StringBuilder url = new StringBuilder(path); + url.append("?appid=").append(auth.getAppId()).append("&refresh_token=").append(refreshToken).append("&grant_type=refresh_token"); + //请求 + ResponseEntity result = externalRestTemplate.getForEntity(url.toString(), String.class); + //解析结果 + Oauth2Token token = objectMapper.readValue(result.getBody(), Oauth2Token.class); + //验证 + WeixinMpConsont.checkResult(token); + //返回 + return token; + } + + /** + * 拉取用户信息(需scope为 snsapi_userinfo) + * + * @param accessToken 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同 + * @param openId 用户的唯一标识 + * @param lang 返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语 + * @return Oauth2UserInfo + * @throws IOException IOException + */ + public Oauth2UserInfo userInfo(String accessToken, String openId, String lang) throws IOException { + //获得接口地址 + String path = weixinMpApiProperties.getSnsPath().get("sns_userinfo"); + //拼接url + StringBuilder url = new StringBuilder(path); + url.append("?access_token=").append(accessToken).append("&openid=").append(openId).append("&lang=").append(lang); + //请求 + ResponseEntity result = externalRestTemplate.getForEntity(url.toString(), String.class); + //解析结果 + Oauth2UserInfo oauth2UserInfo = objectMapper.readValue(result.getBody(), Oauth2UserInfo.class); + //验证 + WeixinMpConsont.checkResult(oauth2UserInfo); + //返回 + return oauth2UserInfo; + } + + /** + * 检验授权凭证(access_token)是否有效 + * + * @param accessToken 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同 + * @param openId 用户的唯一标识 + * @return BaseResult + * @throws IOException IOException + */ + public BaseResult auth(String accessToken, String openId) throws IOException { + //获得接口地址 + String path = weixinMpApiProperties.getSnsPath().get("sns_auth"); + //拼接url + StringBuilder url = new StringBuilder(path); + url.append("?access_token=").append(accessToken).append("&openid=").append(openId); + //请求 + ResponseEntity result = externalRestTemplate.getForEntity(url.toString(), String.class); + //解析结果 + BaseResult baseResult = objectMapper.readValue(result.getBody(), BaseResult.class); + //验证 + WeixinMpConsont.checkResult(baseResult); + //返回 + return baseResult; + } + +} diff --git a/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/WeixinMpApiProperties.java b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/WeixinMpApiProperties.java index 4112be6..1b3727e 100644 --- a/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/WeixinMpApiProperties.java +++ b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/WeixinMpApiProperties.java @@ -20,4 +20,9 @@ public class WeixinMpApiProperties { */ private Map auth; + /** + * sns接口地址 + */ + private Map snsPath; + } diff --git a/udf-starter-weixin-mp/src/main/java/org/itkk/udf/weixin/mp/WeixinMpConsont.java b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/WeixinMpConsont.java similarity index 73% rename from udf-starter-weixin-mp/src/main/java/org/itkk/udf/weixin/mp/WeixinMpConsont.java rename to udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/WeixinMpConsont.java index efe444b..fdd3380 100644 --- a/udf-starter-weixin-mp/src/main/java/org/itkk/udf/weixin/mp/WeixinMpConsont.java +++ b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/WeixinMpConsont.java @@ -1,5 +1,6 @@ -package org.itkk.udf.weixin.mp; +package org.itkk.udf.weixin.mp.api; +import org.itkk.udf.weixin.mp.api.domain.BaseResult; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -24,6 +25,26 @@ public class WeixinMpConsont { } + /** + *

+ * 检查返回值 + *

+ * + * @param br 返回值 + */ + public static void checkResult(BaseResult br) { + //判断是否拿到返回值 + if (br == null) { + //返回异常信息 + throw new WeixinMpException("error"); + } + //是否有错误(0为正常处理) + if (br.getErrcode() != null && !"0".equals(br.getErrcode())) { + //返回异常信息 + throw new WeixinMpException(br.getErrcode() + ":" + br.getErrmsg()); + } + } + /** * 描述 : 获得节点值 * diff --git a/udf-starter-weixin-mp/src/main/java/org/itkk/udf/weixin/mp/WeixinMpException.java b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/WeixinMpException.java similarity index 96% rename from udf-starter-weixin-mp/src/main/java/org/itkk/udf/weixin/mp/WeixinMpException.java rename to udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/WeixinMpException.java index 6b13612..975e4fd 100644 --- a/udf-starter-weixin-mp/src/main/java/org/itkk/udf/weixin/mp/WeixinMpException.java +++ b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/WeixinMpException.java @@ -4,7 +4,7 @@ * Created by wangkang * Copyright (C) 2016 itkk.org, All rights reserved. */ -package org.itkk.udf.weixin.mp; +package org.itkk.udf.weixin.mp.api; /** *

diff --git a/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/domain/BaseResult.java b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/domain/BaseResult.java new file mode 100644 index 0000000..162a390 --- /dev/null +++ b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/domain/BaseResult.java @@ -0,0 +1,32 @@ +package org.itkk.udf.weixin.mp.api.domain; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * BaseResult + */ +@Data +@ApiModel(description = "微信基础返回信息") +public class BaseResult implements Serializable { + /** + * ID + */ + private static final long serialVersionUID = 1L; + + /** + * errcode + */ + @ApiModelProperty(value = "错误代码", required = true, dataType = "string") + private String errcode; + + /** + * errmsg + */ + @ApiModelProperty(value = "错误描述", required = true, dataType = "string") + private String errmsg; + +} diff --git a/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/domain/Oauth2Token.java b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/domain/Oauth2Token.java new file mode 100644 index 0000000..f7f8c17 --- /dev/null +++ b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/domain/Oauth2Token.java @@ -0,0 +1,51 @@ +package org.itkk.udf.weixin.mp.api.domain; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * Oauth2Token + */ +@Data +@EqualsAndHashCode(callSuper = false) +@ApiModel(description = "网页授权token信息") +public class Oauth2Token extends BaseResult { + + /** + * ID + */ + private static final long serialVersionUID = 1L; + + /** + * access_token + */ + @ApiModelProperty(value = "网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同", required = true, dataType = "string") + private String access_token; //NOSONAR + + /** + * expires_in + */ + @ApiModelProperty(value = "ccess_token接口调用凭证超时时间,单位(秒)", required = true, dataType = "int") + private Integer expires_in; //NOSONAR + + /** + * refresh_token + */ + @ApiModelProperty(value = "用户刷新access_token", required = true, dataType = "string") + private String refresh_token; //NOSONAR + + /** + * openid + */ + @ApiModelProperty(value = "用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID", required = true, dataType = "string") + private String openid; + + /** + * scope + */ + @ApiModelProperty(value = "用户授权的作用域,使用逗号(,)分隔", required = true, dataType = "string") + private String scope; + +} diff --git a/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/domain/Oauth2UserInfo.java b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/domain/Oauth2UserInfo.java new file mode 100644 index 0000000..ead4fb0 --- /dev/null +++ b/udf-starter-weixin-mp-api/src/main/java/org/itkk/udf/weixin/mp/api/domain/Oauth2UserInfo.java @@ -0,0 +1,77 @@ +package org.itkk.udf.weixin.mp.api.domain; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * Oauth2Token + */ +@Data +@EqualsAndHashCode(callSuper = false) +@ApiModel(description = "网页授权用户信息") +public class Oauth2UserInfo extends BaseResult { + + /** + * ID + */ + private static final long serialVersionUID = 1L; + + /** + * openid + */ + @ApiModelProperty(value = "用户的唯一标识", required = true, dataType = "string") + private String openid; + + /** + * nickname + */ + @ApiModelProperty(value = "用户昵称", required = true, dataType = "string") + private String nickname; + + /** + * sex + */ + @ApiModelProperty(value = "用户的性别,值为1时是男性,值为2时是女性,值为0时是未知", required = true, dataType = "string") + private String sex; + + /** + * province + */ + @ApiModelProperty(value = "用户个人资料填写的省份", required = true, dataType = "string") + private String province; + + /** + * city + */ + @ApiModelProperty(value = "普通用户个人资料填写的城市", required = true, dataType = "string") + private String city; + + /** + * country + */ + @ApiModelProperty(value = " 国家,如中国为CN", required = true, dataType = "string") + private String country; + + /** + * headimgurl + */ + @ApiModelProperty(value = "用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。", required = true, dataType = "string") + private String headimgurl; + + /** + * privilege + */ + @ApiModelProperty(value = "用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)", required = true, dataType = "array") + private List privilege; + + /** + * unionid + */ + @ApiModelProperty(value = "只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。", required = true, dataType = "string") + private String unionid; + +} diff --git a/udf-starter-weixin-mp/src/main/java/org/itkk/udf/weixin/mp/service/WeixinMpCallbackService.java b/udf-starter-weixin-mp/src/main/java/org/itkk/udf/weixin/mp/service/WeixinMpCallbackService.java index b73efc0..7f16834 100644 --- a/udf-starter-weixin-mp/src/main/java/org/itkk/udf/weixin/mp/service/WeixinMpCallbackService.java +++ b/udf-starter-weixin-mp/src/main/java/org/itkk/udf/weixin/mp/service/WeixinMpCallbackService.java @@ -4,8 +4,8 @@ import com.qq.weixin.mp.aes.WXBizMsgCrypt; import lombok.extern.slf4j.Slf4j; import org.itkk.udf.amqp.rabbitmq.Rabbitmq; import org.itkk.udf.amqp.rabbitmq.RabbitmqMessage; -import org.itkk.udf.weixin.mp.WeixinMpConsont; -import org.itkk.udf.weixin.mp.WeixinMpException; +import org.itkk.udf.weixin.mp.api.WeixinMpConsont; +import org.itkk.udf.weixin.mp.api.WeixinMpException; import org.itkk.udf.weixin.mp.api.ShaOne; import org.itkk.udf.weixin.mp.api.WeixinMpApiConfig; import org.itkk.udf.weixin.mp.api.WeixinMpApiProperties; @@ -73,7 +73,6 @@ public class WeixinMpCallbackService { * @param timestamp timestamp * @param nonce nonce * @param inputMessage inputMessage - * @return String * @throws Exception Exception */ @Async