From 6f7bc7c02c1f84da5a4b333cb86808254aa37850 Mon Sep 17 00:00:00 2001 From: yuanqixun Date: Thu, 19 Mar 2020 09:24:08 +0800 Subject: [PATCH] =?UTF-8?q?:art:=20#1450=20=E4=BC=81=E4=B8=9A=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E4=BC=98=E5=8C=96=E8=8E=B7=E5=8F=96=E4=B8=89=E6=96=B9?= =?UTF-8?q?=E6=8E=88=E6=9D=83=E7=A0=81=E7=9A=84=E6=8E=A5=E5=8F=A3=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 重新实现企业微信三方授权,获取永久授权码返回信息 * 1、增加获取服务商三方预授权URL 2、修复授权后应用图标字段为空的bug Co-authored-by: 袁启勋 --- .../chanjar/weixin/cp/api/WxCpTpService.java | 29 +++ .../cp/api/impl/BaseWxCpTpServiceImpl.java | 25 ++ .../cp/bean/WxCpTpPermanentCodeInfo.java | 220 ++++++++++++++++++ .../weixin/cp/bean/WxCpTpPreauthCode.java | 26 +++ .../weixin/cp/constant/WxCpApiPathConsts.java | 1 + .../api/impl/BaseWxCpTpServiceImplTest.java | 66 ++++++ 6 files changed, 367 insertions(+) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpPermanentCodeInfo.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpPreauthCode.java diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java index edc2f552c..0c9a0a0a4 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java @@ -7,6 +7,7 @@ import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult; import me.chanjar.weixin.cp.bean.WxCpTpCorp; +import me.chanjar.weixin.cp.bean.WxCpTpPermanentCodeInfo; import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; /** @@ -88,8 +89,36 @@ public interface WxCpTpService { * @param authCode . * @return . */ + @Deprecated WxCpTpCorp getPermanentCode(String authCode) throws WxErrorException; + /** + * 获取企业永久授权码信息 + *
+   *   原来的方法实现不全
+   * 
+ * + * @param authCode + * @return + * + * @author yuan + * @since 2020-03-18 + * + * @throws WxErrorException + */ + WxCpTpPermanentCodeInfo getPermanentCodeInfo(String authCode) throws WxErrorException; + + /** + *
+   *   获取预授权链接
+   * 
+ * @param redirectUri 授权完成后的回调网址 + * @param state a-zA-Z0-9的参数值(不超过128个字节),用于第三方自行校验session,防止跨域攻击 + * @return + * @throws WxErrorException + */ + String getPreAuthUrl(String redirectUri,String state) throws WxErrorException; + /** * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求. * diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java index dea5428c1..bbc8e3c18 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java @@ -3,6 +3,7 @@ package me.chanjar.weixin.cp.api.impl; import com.google.common.base.Joiner; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.bean.WxAccessToken; @@ -17,10 +18,14 @@ import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; import me.chanjar.weixin.cp.api.WxCpTpService; import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult; import me.chanjar.weixin.cp.bean.WxCpTpCorp; +import me.chanjar.weixin.cp.bean.WxCpTpPermanentCodeInfo; +import me.chanjar.weixin.cp.bean.WxCpTpPreauthCode; import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; +import org.apache.commons.lang3.StringUtils; import java.io.File; import java.io.IOException; +import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; @@ -123,6 +128,26 @@ public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, Requ return wxCpTpCorp; } + @Override + public WxCpTpPermanentCodeInfo getPermanentCodeInfo(String authCode) throws WxErrorException{ + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("auth_code", authCode); + String result = post(configStorage.getApiUrl(GET_PERMANENT_CODE), jsonObject.toString()); + return WxCpTpPermanentCodeInfo.fromJson(result); + } + + @Override + @SneakyThrows + public String getPreAuthUrl(String redirectUri,String state) throws WxErrorException{ + String result = get(configStorage.getApiUrl(GET_PREAUTH_CODE),null); + WxCpTpPreauthCode preauthCode = WxCpTpPreauthCode.fromJson(result); + String preAuthUrl = "https://open.work.weixin.qq.com/3rdapp/install?suite_id="+configStorage.getSuiteId()+ + "&pre_auth_code="+preauthCode.getPreAuthCode()+"&redirect_uri="+ URLEncoder.encode(redirectUri,"utf-8"); + if(StringUtils.isNotBlank(state)) + preAuthUrl += "&state="+state; + return preAuthUrl; + } + @Override public String get(String url, String queryParam) throws WxErrorException { return execute(SimpleGetRequestExecutor.create(this), url, queryParam); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpPermanentCodeInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpPermanentCodeInfo.java new file mode 100644 index 000000000..c703c28a6 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpPermanentCodeInfo.java @@ -0,0 +1,220 @@ +package me.chanjar.weixin.cp.bean; + +import com.google.gson.annotations.SerializedName; +import lombok.Getter; +import lombok.Setter; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.List; + +/** + * 微信部门. + * + * @author Daniel Qian + */ +@Getter +@Setter +public class WxCpTpPermanentCodeInfo extends WxCpBaseResp { + + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("access_token") + private String accessToken; + + @SerializedName("expires_in") + private Long ExpiresIn; + + @SerializedName("permanent_code") + private String permanentCode; + + /** + * 授权企业信息 + */ + @SerializedName("auth_corp_info") + private AuthCorpInfo authCorpInfo; + + /** + * 授权信息。如果是通讯录应用,且没开启实体应用,是没有该项的。通讯录应用拥有企业通讯录的全部信息读写权限 + */ + @SerializedName("auth_info") + private AuthInfo authInfo; + + /** + * 授权用户信息 + */ + @SerializedName("auth_user_info") + private AuthUserInfo authUserInfo; + + + @Getter + @Setter + public static class AuthCorpInfo { + @SerializedName("corpid") + private String corpId; + + @SerializedName("corp_name") + private String corpName; + + @SerializedName("corp_type") + private String corpType; + + @SerializedName("corp_square_logo_url") + private String corpSquareLogoUrl; + + @SerializedName("corp_round_logo_url") + private String corpRoundLogoUrl; + + @SerializedName("corp_user_max") + private String corpUserMax; + + @SerializedName("corp_agent_max") + private String corpAgentMax; + + /** + * 所绑定的企业微信主体名称(仅认证过的企业有) + */ + @SerializedName("corp_full_name") + private String corpFullName; + + /** + * 认证到期时间 + */ + @SerializedName("verified_end_time") + private Long verifiedEndTime; + + /** + * 企业类型,1. 企业; 2. 政府以及事业单位; 3. 其他组织, 4.团队号 + */ + @SerializedName("subject_type") + private Integer subjectType; + + /** + * 授权企业在微工作台(原企业号)的二维码,可用于关注微工作台 + */ + @SerializedName("corp_wxqrcode") + private String corpWxqrcode; + + @SerializedName("corp_scale") + private String corpScale; + + @SerializedName("corp_industry") + private String corpIndustry; + + @SerializedName("corp_sub_industry") + private String corpSubIndustry; + + @SerializedName("location") + private String location; + + } + + /** + * 授权信息 + */ + @Getter + @Setter + public static class AuthInfo { + + /** + * 授权的应用信息,注意是一个数组,但仅旧的多应用套件授权时会返回多个agent,对新的单应用授权,永远只返回一个agent + */ + @SerializedName("agent") + private List agent; + + } + + @Getter + @Setter + public static class Agent { + @SerializedName("agentid") + private Integer agentid; + + @SerializedName("name") + private String name; + + @SerializedName("round_logo_url") + private String roundLogoUrl; + + @SerializedName("square_logo_url") + private String squareLogoUrl; + + /** + * 旧的多应用套件中的对应应用id,新开发者请忽略 + */ + @SerializedName("appid") + @Deprecated + private String appid; + + /** + * 应用权限 + */ + @SerializedName("privilege") + private Privilege privilege; + + } + + /** + * 授权人员信息 + */ + @Getter + @Setter + public static class AuthUserInfo { + @SerializedName("userid") + private String userid; + + @SerializedName("name") + private String name; + + @SerializedName("avatar") + private String avatar; + } + + /** + * 应用对应的权限 + */ + @Getter + @Setter + public static class Privilege { + + /** + * 权限等级。 + * 1:通讯录基本信息只读 + * 2:通讯录全部信息只读 + * 3:通讯录全部信息读写 + * 4:单个基本信息只读 + * 5:通讯录全部信息只写 + */ + @SerializedName("level") + private Integer level; + + @SerializedName("allow_party") + private List allowParty; + + @SerializedName("allow_user") + private List allowUser; + + @SerializedName("allow_tag") + private List allowTag; + + @SerializedName("extra_party") + private List extraParty; + + @SerializedName("extra_user") + private List extraUser; + + @SerializedName("extra_tag") + private List extraTag; + + + } + + + public static WxCpTpPermanentCodeInfo fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpTpPermanentCodeInfo.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpPreauthCode.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpPreauthCode.java new file mode 100644 index 000000000..8c102ae4a --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpPreauthCode.java @@ -0,0 +1,26 @@ +package me.chanjar.weixin.cp.bean; + +import com.google.gson.annotations.SerializedName; +import lombok.Getter; +import lombok.Setter; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +/** + * 预授权码返回 + * @author yqx + * @date 2020/3/19 + */ +@Getter +@Setter +public class WxCpTpPreauthCode extends WxCpBaseResp { + + @SerializedName("pre_auth_code") + String preAuthCode; + + @SerializedName("expires_in") + Long expiresIn; + + public static WxCpTpPreauthCode fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpTpPreauthCode.class); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java index 0bee3f42a..da3774ca8 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java @@ -93,6 +93,7 @@ public final class WxCpApiPathConsts { public static final String GET_PERMANENT_CODE = "/cgi-bin/service/get_permanent_code"; public static final String GET_SUITE_TOKEN = "/cgi-bin/service/get_suite_token"; public static final String GET_PROVIDER_TOKEN = "/cgi-bin/service/get_provider_token"; + public static final String GET_PREAUTH_CODE = "/cgi-bin/service/get_pre_auth_code"; } public static class User { diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImplTest.java index 5de54f545..e8e813b04 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImplTest.java @@ -5,6 +5,7 @@ import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.api.WxCpTpService; import me.chanjar.weixin.cp.bean.WxCpTpCorp; +import me.chanjar.weixin.cp.bean.WxCpTpPermanentCodeInfo; import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl; import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; @@ -128,6 +129,71 @@ public class BaseWxCpTpServiceImplTest { final WxCpTpCorp tpCorp = tpService.getPermanentCode(authCode); assertThat(tpCorp.getPermanentCode()).isEqualTo("xxxx"); + + final WxCpTpPermanentCodeInfo tpPermanentCodeInfo = tpService.getPermanentCodeInfo(authCode); + assertThat(tpPermanentCodeInfo.getAuthInfo().getAgent().get(0).getAgentid()).isEqualTo(1); + + } + + @Test + public void testGetPermanentCodeInfo() throws WxErrorException{ + String returnJson = "{\n" + + " \"access_token\": \"u6SoEWyrEmworJ1uNzddbiXh42mCLNU_mdd6b01Afo2LKmyi-WdaaYqhEGFZjB1RGZ-rhjLcAJ86ger7b7Q0gowSw9iIDR8dm49aVH_MztzmQttP3XFG7np1Dxs_VQkVwhhRmfRpEonAmK1_JWIFqayJXXiPUS3LsFd3tWpE7rxmsRa7Ev2ml2htbRp_qGUjtFTErKoDsnNGSka6_RqFPA\", \n" + + " \"expires_in\": 7200, \n" + + " \"permanent_code\": \"lMLlxss77ntxzuEl1i1_AQ3-6-cvqMLYs209YNWVruk\", \n" + + " \"auth_corp_info\": {\n" + + " \"corpid\": \"xxxcorpid\", \n" + + " \"corp_name\": \"xxxx有限公司\", \n" + + " \"corp_type\": \"unverified\", \n" + + " \"corp_round_logo_url\": \"http://p.qpic.cn/pic_wework/3777001839/4046834be7a5f2711feaaa3cc4e691e1bcb1e526cb4544b5/0\", \n" + + " \"corp_square_logo_url\": \"https://p.qlogo.cn/bizmail/EsvsszIt9hJrjrx8QKXuIs0iczdnV4icaPibLIViaukn1iazCay8L1UXtibA/0\", \n" + + " \"corp_user_max\": 200, \n" + + " \"corp_agent_max\": 300, \n" + + " \"corp_wxqrcode\": \"http://p.qpic.cn/pic_wework/211781738/a9af41a60af7519775dd7ac846a4942979dc4a14b8bb2c72/0\", \n" + + " \"corp_full_name\": \"xxxx有限公司\", \n" + + " \"subject_type\": 1, \n" + + " \"corp_scale\": \"1-50人\", \n" + + " \"corp_industry\": \"生活服务\", \n" + + " \"corp_sub_industry\": \"租赁和商务服务\", \n" + + " \"location\": \"北京市\"\n" + + " }, \n" + + " \"auth_info\": {\n" + + " \"agent\": [\n" + + " {\n" + + " \"agentid\": 1000012, \n" + + " \"name\": \"xxxxx\", \n" + + " \"square_logo_url\": \"http://wx.qlogo.cn/mmhead/Q3auHgzwzM4ZCtdxicN8ghMOtTv7M7rLPKmeZ3amic00btdwbNmicaW3Q/0\", \n" + + " \"privilege\": {\n" + + " \"level\": 1, \n" + + " \"allow_party\": [ ], \n" + + " \"allow_user\": [\n" + + " \"yuanqixun\"\n" + + " ], \n" + + " \"allow_tag\": [ ], \n" + + " \"extra_party\": [ ], \n" + + " \"extra_user\": [ ], \n" + + " \"extra_tag\": [ ]\n" + + " }\n" + + " }\n" + + " ]\n" + + " }, \n" + + " \"auth_user_info\": {\n" + + " \"userid\": \"yuanqixun\", \n" + + " \"name\": \"袁启勋\", \n" + + " \"avatar\": \"http://wework.qpic.cn/bizmail/ZYqy8EswiaFyPnk7gy7eiafoicz3TL35f4bAvCf2eSe6RVYSK7aPDFxcw/0\"\n" + + " }\n" + + "}"; + + final WxCpTpConfigStorage configStorage = new WxCpTpDefaultConfigImpl(); + tpService.setWxCpTpConfigStorage(configStorage); + JsonObject jsonObject = new JsonObject(); + String authCode = ""; + jsonObject.addProperty("auth_code", authCode); + doReturn(returnJson).when(tpService).post(configStorage.getApiUrl(GET_PERMANENT_CODE), jsonObject.toString()); + final WxCpTpPermanentCodeInfo tpPermanentCodeInfo = tpService.getPermanentCodeInfo(authCode); + assertThat(tpPermanentCodeInfo.getAuthInfo().getAgent().get(0).getAgentid()).isEqualTo(1000012); + assertNotNull(tpPermanentCodeInfo.getAuthInfo().getAgent().get(0).getSquareLogoUrl()); + assertNotNull(tpPermanentCodeInfo.getAuthCorpInfo().getCorpSquareLogoUrl()); } @Test