新增第三方组件ComponentApi

This commit is contained in:
jinyu 2016-07-05 23:34:17 +08:00
parent 135b1318f5
commit ff349fd370
19 changed files with 804 additions and 180 deletions

View File

@ -722,3 +722,5 @@
* 2016-07-05 * 2016-07-05
+ weixin4j-mp:初始化开放平台第三方组件TokenCreator + weixin4j-mp:初始化开放平台第三方组件TokenCreator
+ weixin4j-mp:新增第三方组件ComponentApi

View File

@ -18,11 +18,11 @@ public class TicketManager {
/** /**
* 第三方ID * 第三方ID
*/ */
private final String id; private final String thirdId;
/** /**
* 第三方secret * 第三方secret
*/ */
private final String secret; private final String thirdSecret;
/** /**
* ticket存储策略 * ticket存储策略
*/ */
@ -30,27 +30,38 @@ public class TicketManager {
/** /**
* *
* @param id * @param thirdId
* 第三方ID * 第三方ID suiteId/componentId
* @param secret * @param thirdSecret
* 第三方secret * 第三方secret
* @param cacheStorager * @param cacheStorager
* ticket存储策略 * ticket存储策略
*/ */
public TicketManager(String id, String secret, CacheStorager<Token> cacheStorager) { public TicketManager(String thirdId, String thirdSecret,
this.id = id; CacheStorager<Token> cacheStorager) {
this.secret = secret; this.thirdId = thirdId;
this.thirdSecret = thirdSecret;
this.cacheStorager = cacheStorager; this.cacheStorager = cacheStorager;
} }
/**
* 获取ticket对象
*
* @return token对象
* @throws WeixinException
*/
public Token getTicket() throws WeixinException {
return cacheStorager.lookup(getCacheKey());
}
/** /**
* 获取ticket * 获取ticket
* *
* @return * @return ticket
* @throws WeixinException * @throws WeixinException
*/ */
public String getTicket() throws WeixinException { public String getAccessTicket() throws WeixinException {
return cacheStorager.lookup(getCacheKey()).getAccessToken(); return getTicket().getAccessToken();
} }
/** /**
@ -59,13 +70,15 @@ public class TicketManager {
* @return * @return
*/ */
public String getCacheKey() { public String getCacheKey() {
return String.format("%sthird_party_ticket_%s", TokenCreator.CACHEKEY_PREFIX, id); return String.format("%sthird_party_ticket_%s",
TokenCreator.CACHEKEY_PREFIX, thirdId);
} }
/** /**
* 缓存ticket * 缓存ticket
* *
* @param ticket * @param ticket
* 票据凭证
* @throws WeixinException * @throws WeixinException
*/ */
public void cachingTicket(String ticket) throws WeixinException { public void cachingTicket(String ticket) throws WeixinException {
@ -73,12 +86,12 @@ public class TicketManager {
cacheStorager.caching(getCacheKey(), token); cacheStorager.caching(getCacheKey(), token);
} }
public String getId() { public String getThirdId() {
return id; return thirdId;
} }
public String getSecret() { public String getThirdSecret() {
return secret; return thirdSecret;
} }
public CacheStorager<Token> getCacheStorager() { public CacheStorager<Token> getCacheStorager() {

View File

@ -233,3 +233,5 @@
* 2016-07-05 * 2016-07-05
+ 初始化开放平台第三方组件TokenCreator + 初始化开放平台第三方组件TokenCreator
+ 新增第三方组件ComponentApi

View File

@ -26,6 +26,7 @@ import com.foxinmy.weixin4j.mp.api.QrApi;
import com.foxinmy.weixin4j.mp.api.TagApi; import com.foxinmy.weixin4j.mp.api.TagApi;
import com.foxinmy.weixin4j.mp.api.TmplApi; import com.foxinmy.weixin4j.mp.api.TmplApi;
import com.foxinmy.weixin4j.mp.api.UserApi; import com.foxinmy.weixin4j.mp.api.UserApi;
import com.foxinmy.weixin4j.mp.component.WeixinTokenComponentCreator;
import com.foxinmy.weixin4j.mp.message.NotifyMessage; import com.foxinmy.weixin4j.mp.message.NotifyMessage;
import com.foxinmy.weixin4j.mp.message.TemplateMessage; import com.foxinmy.weixin4j.mp.message.TemplateMessage;
import com.foxinmy.weixin4j.mp.model.AutoReplySetting; import com.foxinmy.weixin4j.mp.model.AutoReplySetting;
@ -51,6 +52,7 @@ import com.foxinmy.weixin4j.mp.type.DatacubeType;
import com.foxinmy.weixin4j.mp.type.IndustryType; import com.foxinmy.weixin4j.mp.type.IndustryType;
import com.foxinmy.weixin4j.mp.type.Lang; import com.foxinmy.weixin4j.mp.type.Lang;
import com.foxinmy.weixin4j.setting.Weixin4jSettings; import com.foxinmy.weixin4j.setting.Weixin4jSettings;
import com.foxinmy.weixin4j.token.PerTicketManager;
import com.foxinmy.weixin4j.token.TokenManager; import com.foxinmy.weixin4j.token.TokenManager;
import com.foxinmy.weixin4j.tuple.MassTuple; import com.foxinmy.weixin4j.tuple.MassTuple;
import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.tuple.MpArticle;
@ -149,6 +151,25 @@ public class WeixinProxy {
this.settings = settings; this.settings = settings;
} }
/**
* 第三方组件(永久刷新令牌机制)
*
* @param perTicketManager
* 第三方组件永久刷新令牌
* {@link com.foxinmy.weixin4j.mp.api.ComponentApi#getPerCodeManager(String)}
* @param componentTokenManager
* 第三方组件凭证token
* {@link com.foxinmy.weixin4j.mp.api.ComponentApi#getTokenManager}
* @see com.foxinmy.weixin4j.mp.api.ComponentApi
*/
public WeixinProxy(PerTicketManager perTicketManager,
TokenManager componentTokenManager) {
this(new TokenManager(new WeixinTokenComponentCreator(perTicketManager,
componentTokenManager), perTicketManager.getCacheStorager()));
this.settings = new Weixin4jSettings<WeixinAccount>(new WeixinAccount(
perTicketManager.getAuthAppId(), null));
}
/** /**
* 注意TokenCreator 需为 <font color="red">WeixinTokenCreator</font> * 注意TokenCreator 需为 <font color="red">WeixinTokenCreator</font>
* *

View File

@ -1,8 +1,24 @@
package com.foxinmy.weixin4j.mp.api; package com.foxinmy.weixin4j.mp.api;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.JsonResult;
import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.component.WeixinComponentPreCodeCreator; import com.foxinmy.weixin4j.mp.component.WeixinComponentPreCodeCreator;
import com.foxinmy.weixin4j.mp.component.WeixinComponentTokenCreator; import com.foxinmy.weixin4j.mp.component.WeixinComponentTokenCreator;
import com.foxinmy.weixin4j.mp.component.WeixinTokenComponentCreator;
import com.foxinmy.weixin4j.mp.model.AuthorizerOption;
import com.foxinmy.weixin4j.mp.model.AuthorizerOption.AuthorizerOptionName;
import com.foxinmy.weixin4j.mp.model.ComponentAuthInfo;
import com.foxinmy.weixin4j.token.PerTicketManager;
import com.foxinmy.weixin4j.token.TicketManager; import com.foxinmy.weixin4j.token.TicketManager;
import com.foxinmy.weixin4j.token.TokenCreator;
import com.foxinmy.weixin4j.token.TokenManager; import com.foxinmy.weixin4j.token.TokenManager;
/** /**
@ -36,9 +52,11 @@ public class ComponentApi extends MpApi {
*/ */
public ComponentApi(TicketManager ticketManager) { public ComponentApi(TicketManager ticketManager) {
this.ticketManager = ticketManager; this.ticketManager = ticketManager;
this.tokenManager = new TokenManager(new WeixinComponentTokenCreator(ticketManager), this.tokenManager = new TokenManager(new WeixinComponentTokenCreator(
ticketManager.getCacheStorager()); ticketManager), ticketManager.getCacheStorager());
this.preCodeManager = new TokenManager(new WeixinComponentPreCodeCreator(tokenManager, ticketManager.getId()), this.preCodeManager = new TokenManager(
new WeixinComponentPreCodeCreator(tokenManager,
ticketManager.getThirdId()),
ticketManager.getCacheStorager()); ticketManager.getCacheStorager());
} }
@ -68,4 +86,153 @@ public class ComponentApi extends MpApi {
public TokenManager getPreCodeManager() { public TokenManager getPreCodeManager() {
return this.preCodeManager; return this.preCodeManager;
} }
/**
* 应用套组件永久刷新令牌:刷新令牌主要用于公众号第三方平台获取和刷新已授权用户的access_token只会在授权时刻提供请妥善保存
* 一旦丢失只能让用户重新授权才能再次拿到新的刷新令牌
*
* @param authAppId
* 授权方appid
* @return
*/
public PerTicketManager getRefreshTokenManager(String authAppId) {
return new PerTicketManager(authAppId, ticketManager.getThirdId(),
ticketManager.getThirdSecret(),
ticketManager.getCacheStorager());
}
/**
* 使用授权码换取公众号的接口调用凭据和授权信息:用于使用授权码换取授权公众号的授权信息
* 并换取authorizer_access_token和authorizer_refresh_token
* 授权码的获取需要在用户在第三方平台授权页中完成授权流程后
* 在回调URI中通过URL参数提供给第三方平台方请注意由于现在公众号可以自定义选择部分权限授权给第三方平台
* 因此第三方平台开发者需要通过该接口来获取公众号具体授权了哪些权限而不是简单地认为自己声明的权限就是公众号授权的权限
*
* @param authCode
* 授权code
* @return 第三方组件授权信息
* @see com.foxinmy.weixin4j.mp.model.ComponentAuthInfo
* @throws WeixinException
*/
public ComponentAuthInfo exchangeComponentAuthInfo(String authCode)
throws WeixinException {
String component_exchange_authorizer_uri = getRequestUri("component_exchange_authorizer_uri");
JSONObject obj = new JSONObject();
obj.put("component_appid", ticketManager.getThirdId());
obj.put("authorization_code", authCode);
WeixinResponse response = weixinExecutor.post(
String.format(component_exchange_authorizer_uri,
tokenManager.getAccessToken()), obj.toJSONString());
obj = response.getAsJson();
JSONObject authObj = obj.getJSONObject("authorization_info");
JSONArray privilegesObj = authObj.getJSONArray("func_info");
List<Integer> privileges = new ArrayList<Integer>(privilegesObj.size());
for (int i = 0; i < privilegesObj.size(); i++) {
privileges.add(privilegesObj.getJSONObject(i)
.getJSONObject("funcscope_category").getInteger("id"));
}
ComponentAuthInfo info = new ComponentAuthInfo();
info.setPrivileges(privileges);
info.setAppId(authObj.getString("authorizer_appid"));
// 微信授权公众号的永久刷新令牌
PerTicketManager perTicketManager = getRefreshTokenManager(info
.getAppId());
// 缓存微信公众号的access_token
TokenCreator tokenCreator = new WeixinTokenComponentCreator(
perTicketManager, tokenManager);
Token token = new Token(authObj.getString("authorizer_access_token"),
authObj.getLongValue("expires_in") * 1000l);
ticketManager.getCacheStorager().caching(tokenCreator.key(), token);
// 缓存微信企业号的永久授权码
perTicketManager.cachingTicket(authObj
.getString("authorizer_refresh_token"));
return info;
}
/**
* 获取授权方的公众号帐号基本信息:获取授权方的公众号基本信息包括头像昵称帐号类型认证类型微信号原始ID和二维码图片URL
* 需要特别记录授权方的帐号类型在消息及事件推送时对于不具备客服接口的公众号需要在5秒内立即响应而若有客服接口则可以选择暂时不响应
* 而选择后续通过客服接口来发送消息触达粉丝
*
* @param authAppId
* 授权方appid
* @return 第三方组件授权信息
* @see com.foxinmy.weixin4j.mp.model.ComponentAuthInfo
* @throws WeixinException
*/
public ComponentAuthInfo getComponentAuthInfo(String authAppId)
throws WeixinException {
String component_get_authorizer_uri = getRequestUri("component_get_authorizer_uri");
JSONObject obj = new JSONObject();
obj.put("component_appid", ticketManager.getThirdId());
obj.put("authorizer_appid", authAppId);
WeixinResponse response = weixinExecutor.post(
String.format(component_get_authorizer_uri,
tokenManager.getAccessToken()), obj.toJSONString());
obj = response.getAsJson().getJSONObject("authorizer_info");
ComponentAuthInfo info = JSON
.toJavaObject(obj, ComponentAuthInfo.class);
info.setServiceType(obj.getJSONObject("service_type_info").getIntValue(
"id"));
info.setVerifyType(obj.getJSONObject("verify_type_info").getIntValue(
"id"));
JSONArray privilegesObj = obj.getJSONObject("authorization_info")
.getJSONArray("func_info");
List<Integer> privileges = new ArrayList<Integer>(privilegesObj.size());
for (int i = 0; i < privilegesObj.size(); i++) {
privileges.add(privilegesObj.getJSONObject(i)
.getJSONObject("funcscope_category").getInteger("id"));
}
info.setPrivileges(privileges);
info.setAppId(authAppId);
return info;
}
/**
* 获取授权方的公众号的选项设置信息地理位置上报语音识别开关多客服开关注意获取各项选项设置信息
*
* @param authAppId
* 授权方appid
* @param option
* 选项名称
* @return 选项信息
* @see com.foxinmy.weixin4j.mp.model.AuthorizerOption
* @throws WeixinException
*/
public AuthorizerOption getAuthorizerOption(String authAppId,
AuthorizerOptionName optionName) throws WeixinException {
String component_get_authorizer_option_uri = getRequestUri("component_get_authorizer_option_uri");
JSONObject obj = new JSONObject();
obj.put("component_appid", ticketManager.getThirdId());
obj.put("authorizer_appid", authAppId);
obj.put("option_name", optionName.name());
WeixinResponse response = weixinExecutor.post(
String.format(component_get_authorizer_option_uri,
tokenManager.getAccessToken()), obj.toJSONString());
int optionValue = response.getAsJson().getIntValue("option_value");
return AuthorizerOption.parse(optionName, optionValue);
}
/**
* 设置授权方的公众号的选项信息地理位置上报语音识别开关多客服开关注意获取各项选项设置信息
*
* @param option
* 选项信息
* @return 设置标识
* @see com.foxinmy.weixin4j.mp.model.AuthorizerOption
* @throws WeixinException
*/
public JsonResult getAuthorizerOption(String authAppId,
AuthorizerOption option) throws WeixinException {
String component_set_authorizer_option_uri = getRequestUri("component_set_authorizer_option_uri");
JSONObject obj = new JSONObject();
obj.put("component_appid", ticketManager.getThirdId());
obj.put("authorizer_appid", authAppId);
obj.put("option_name", option.getName());
obj.put("option_value", option.getValue());
WeixinResponse response = weixinExecutor.post(
String.format(component_set_authorizer_option_uri,
tokenManager.getAccessToken()), obj.toJSONString());
return response.getAsJsonResult();
}
} }

View File

@ -45,7 +45,7 @@ public class OauthApi extends MpApi {
} }
/** /**
* base静默授权:重定向URL使用weixin4j.properties#user.oauth.redirect.uri * 公众号base静默oauth授权:重定向URL使用weixin4j.properties#user.oauth.redirect.uri
* *
* @see {@link #getAuthorizeURL(String, String,String)} * @see {@link #getAuthorizeURL(String, String,String)}
* *
@ -205,4 +205,38 @@ public class OauthApi extends MpApi {
return response.getAsObject(new TypeReference<User>() { return response.getAsObject(new TypeReference<User>() {
}); });
} }
/**
* 微信开放平台oauth授权:重定向URL使用weixin4j.properties#user.oauth.redirect.uri
*
* @see {@link #getOpenAuthorizeURL(String, String)}
*
* @return 请求授权的URL
*/
public String getOpenAuthorizeURL() {
String redirectUri = Weixin4jConfigUtil
.getValue("user.oauth.redirect.uri");
return getOpenAuthorizeURL(redirectUri, "state");
}
/**
* 请求CODE
*
* @param redirectUri
* 重定向地址 域名与审核时填写的授权域名一致
* @param state
* 用于保持请求和回调的状态授权请求后原样带回给第三方
* @return 请求授权的URL
*/
public String getOpenAuthorizeURL(String redirectUri, String state) {
String open_user_auth_uri = getRequestUri("open_user_auth_uri");
try {
return String.format(open_user_auth_uri, account.getId(),
URLEncoder.encode(redirectUri, Consts.UTF_8.name()),
"snsapi_login", state);
} catch (UnsupportedEncodingException e) {
;
}
return "";
}
} }

View File

@ -11,11 +11,11 @@ tenpay_gw_base_url=https://gw.tenpay.com
# \u7f51\u9875\u6388\u6743\u83b7\u53d6\u7528\u6237\u4fe1\u606f # \u7f51\u9875\u6388\u6743\u83b7\u53d6\u7528\u6237\u4fe1\u606f
sns_user_auth_uri=https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect sns_user_auth_uri=https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect
#open_user_auth_uri=https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect
sns_user_token_uri=https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code sns_user_token_uri=https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code
sns_token_refresh_uri=https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s sns_token_refresh_uri=https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s
sns_auth_token_uri=https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s sns_auth_token_uri=https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s
sns_user_info_uri=https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s sns_user_info_uri=https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s
open_user_auth_uri=https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect
# \u76f4\u63a5\u83b7\u53d6\u7528\u6237\u4fe1\u606f # \u76f4\u63a5\u83b7\u53d6\u7528\u6237\u4fe1\u606f
api_user_info_uri={api_cgi_url}/user/info?access_token=%s&openid=%s&lang=%s api_user_info_uri={api_cgi_url}/user/info?access_token=%s&openid=%s&lang=%s
@ -179,3 +179,12 @@ tag_untagging_uri={api_cgi_url}/tags/members/batchuntagging?access_token=%s
tag_userids_uri={api_cgi_url}/tags/getidlist?access_token=%s tag_userids_uri={api_cgi_url}/tags/getidlist?access_token=%s
# \u83b7\u53d6\u6807\u7b7e\u4e0b\u7c89\u4e1d\u5217\u8868 # \u83b7\u53d6\u6807\u7b7e\u4e0b\u7c89\u4e1d\u5217\u8868
tag_user_uri={api_cgi_url}/user/tag/get?access_token=%s tag_user_uri={api_cgi_url}/user/tag/get?access_token=%s
# \u4f7f\u7528\u6388\u6743\u7801\u6362\u53d6\u516c\u4f17\u53f7\u7684\u63a5\u53e3\u8c03\u7528\u51ed\u636e\u548c\u6388\u6743\u4fe1\u606f
component_exchange_authorizer_uri={api_cgi_url}/component/api_query_auth?component_access_token=%s
# \u83b7\u53d6\u6388\u6743\u65b9\u7684\u516c\u4f17\u53f7\u5e10\u53f7\u57fa\u672c\u4fe1\u606f
component_get_authorizer_uri={api_cgi_url}/component/api_get_authorizer_info?component_access_token=%s
# \u83b7\u53d6\u6388\u6743\u65b9\u7684\u9009\u9879\u8bbe\u7f6e\u4fe1\u606f
component_get_authorizer_option_uri={api_cgi_url}/component/api_get_authorizer_option?component_access_token=%s
# \u8bbe\u7f6e\u6388\u6743\u65b9\u7684\u9009\u9879\u4fe1\u606f
component_set_authorizer_option_uri={api_cgi_url}component/api_set_authorizer_option?component_access_token=%s

View File

@ -9,7 +9,7 @@ import com.foxinmy.weixin4j.token.TokenCreator;
import com.foxinmy.weixin4j.token.TokenManager; import com.foxinmy.weixin4j.token.TokenManager;
/** /**
* 微信企业号应用套件预授权码创建 * 微信开发平台应用组件预授权码创建
* *
* @className WeixinComponentPreCodeCreator * @className WeixinComponentPreCodeCreator
* @author jinyu(foxinmy@gmail.com) * @author jinyu(foxinmy@gmail.com)

View File

@ -9,7 +9,7 @@ import com.foxinmy.weixin4j.token.TicketManager;
import com.foxinmy.weixin4j.token.TokenCreator; import com.foxinmy.weixin4j.token.TokenCreator;
/** /**
* 微信公众号应用组件凭证创建 * 微信开发平台应用组件凭证创建
* *
* @className WeixinComponentTokenCreator * @className WeixinComponentTokenCreator
* @author jinyu(foxinmy@gmail.com) * @author jinyu(foxinmy@gmail.com)
@ -30,19 +30,19 @@ public class WeixinComponentTokenCreator extends TokenCreator {
@Override @Override
public String key0() { public String key0() {
return String.format("mp_component_token_%s", ticketManager.getId()); return String.format("mp_component_token_%s", ticketManager.getThirdId());
} }
@Override @Override
public Token create() throws WeixinException { public Token create() throws WeixinException {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("component_appid", ticketManager.getId()); obj.put("component_appid", ticketManager.getThirdId());
obj.put("component_appsecret", ticketManager.getSecret()); obj.put("component_appsecret", ticketManager.getThirdSecret());
obj.put("component_verify_ticket", ticketManager.getTicket()); obj.put("component_verify_ticket", ticketManager.getAccessTicket());
WeixinResponse response = weixinExecutor.post( WeixinResponse response = weixinExecutor.post(
URLConsts.COMPONENT_TOKEN_URL, obj.toJSONString()); URLConsts.COMPONENT_TOKEN_URL, obj.toJSONString());
obj = response.getAsJson(); obj = response.getAsJson();
return new Token(obj.getString("suite_access_token"), return new Token(obj.getString("component_access_token"),
obj.getLongValue("expires_in") * 1000l); obj.getLongValue("expires_in") * 1000l);
} }
} }

View File

@ -0,0 +1,57 @@
package com.foxinmy.weixin4j.mp.component;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.type.URLConsts;
import com.foxinmy.weixin4j.token.PerTicketManager;
import com.foxinmy.weixin4j.token.TokenCreator;
import com.foxinmy.weixin4j.token.TokenManager;
/**
* 微信公众号token创建(永久刷新令牌)
*
* @className WeixinTokenComponentCreator
* @author jinyu(foxinmy@gmail.com)
* @date 2016年7月5日
* @since JDK 1.6
*/
public class WeixinTokenComponentCreator extends TokenCreator {
private final PerTicketManager perTicketManager;
private final TokenManager componentTokenManager;
/**
*
* @param perTicketManager
* 第三方套件永久授权码
* @param componentTokenManager
* 第三方套件凭证token
*/
public WeixinTokenComponentCreator(PerTicketManager perTicketManager,
TokenManager componentTokenManager) {
this.perTicketManager = perTicketManager;
this.componentTokenManager = componentTokenManager;
}
@Override
public String key0() {
return String.format("mp_token_suite_%s_%s",
perTicketManager.getThirdId(), perTicketManager.getAuthAppId());
}
@Override
public Token create() throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("component_appid", perTicketManager.getThirdId());
obj.put("authorizer_appid", perTicketManager.getAuthAppId());
obj.put("authorizer_refresh_token", perTicketManager.getAccessTicket());
WeixinResponse response = weixinExecutor.post(
String.format(URLConsts.TOKEN_COMPONENT_URL,
componentTokenManager.getAccessToken()), obj.toJSONString());
obj = response.getAsJson();
return new Token(obj.getString("access_token"),
obj.getLongValue("expires_in") * 1000l);
}
}

View File

@ -0,0 +1,128 @@
package com.foxinmy.weixin4j.mp.model;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
/**
* 授权方的选项信息
*
* @className AuthorizerOption
* @author jinyu(foxinmy@gmail.com)
* @date 2016年7月5日
* @since JDK 1.6
*/
public final class AuthorizerOption implements Serializable {
private static final long serialVersionUID = -3124882411789627403L;
/**
* 选项名称
*
* @className AuthorizerOptionName
* @author jinyu(foxinmy@gmail.com)
* @date 2016年7月5日
* @since JDK 1.6
*/
public enum AuthorizerOptionName {
/**
* 地理位置上报选项
*/
location_report,
/**
* 语音识别开关选项
*/
voice_recognize,
/**
* 多客服开关选项
*/
customer_service;
}
private AuthorizerOptionName name;
private int value;
private List<Integer> options;
private AuthorizerOption(AuthorizerOptionName name, int value,
Integer... options) {
this.name = name;
this.value = value;
this.options = Arrays.asList(options);
}
/**
* 地理位置上报选项
*
* @param value
* 选项值
* @return 选项对象
*/
public static AuthorizerOption createLocationReportOption(int value) {
return new AuthorizerOption(AuthorizerOptionName.location_report,
value, 0, 1, 2);
}
/**
* 语音识别开关选项
*
* @param value
* 选项值
* @return 选项对象
*/
public static AuthorizerOption createVoiceRecognizeOption(int value) {
return new AuthorizerOption(AuthorizerOptionName.voice_recognize,
value, 0, 1);
}
/**
* 多客服开关选项
*
* @param value
* 选项值
* @return 选项对象
*/
public static AuthorizerOption createCustomerServiceOption(int value) {
return new AuthorizerOption(AuthorizerOptionName.customer_service,
value, 0, 1);
}
/**
* 返回选项对象
*
* @param optionName
* 选项名
* @param optionValue
* 选项值
* @return 选项对象
*/
public static AuthorizerOption parse(AuthorizerOptionName optionName,
int optionValue) {
if (optionName == AuthorizerOptionName.customer_service) {
return createCustomerServiceOption(optionValue);
} else if (optionName == AuthorizerOptionName.location_report) {
return createLocationReportOption(optionValue);
} else if (optionName == AuthorizerOptionName.voice_recognize) {
return createVoiceRecognizeOption(optionValue);
} else {
throw new IllegalArgumentException("unkown option:" + optionName);
}
}
public AuthorizerOptionName getName() {
return name;
}
public int getValue() {
return value;
}
public List<Integer> getOptions() {
return options;
}
@Override
public String toString() {
return "AuthorizerOption [name=" + name + ", value=" + value
+ ", options=" + options + "]";
}
}

View File

@ -0,0 +1,235 @@
package com.foxinmy.weixin4j.mp.model;
import java.io.Serializable;
import java.util.List;
import com.alibaba.fastjson.annotation.JSONField;
/**
* 第三方组件授权信息
*
* @className ComponentAuthInfo
* @author jinyu(foxinmy@gmail.com)
* @date 2016年7月5日
* @since JDK 1.6
*/
public class ComponentAuthInfo implements Serializable {
private static final long serialVersionUID = -3610172415045923599L;
/**
* 授权方appId
*/
@JSONField(name = "appid")
private String appId;
/**
* 授权方昵称
*/
@JSONField(name = "nick_name")
private String nickName;
/**
* 授权方头像
*/
@JSONField(name = "head_img")
private String headImg;
/**
* 授权方公众号类型0代表订阅号1代表由历史老帐号升级后的订阅号2代表服务号
*/
@JSONField(deserialize = false)
private int serviceType;
/**
* 授权方认证类型-1代表未认证0代表微信认证1代表新浪微博认证2代表腾讯微博认证3代表已资质认证通过但还未通过名称认证4
* 代表已资质认证通过还未通过名称认证但通过了新浪微博认证5代表已资质认证通过还未通过名称认证但通过了腾讯微博认证
*/
@JSONField(deserialize = false)
private int verifyType;
/**
* 授权方公众号的原始ID
*/
@JSONField(name = "user_name")
private String userName;
/**
* 授权方公众号所设置的微信号可能为空
*/
@JSONField(name = "alias")
private String alias;
/**
* 二维码图片的URL开发者最好自行也进行保存
*/
@JSONField(name = "qrcode_url")
private String qrcodeUrl;
/**
* 公众号功能的开通状况
*/
@JSONField(name = "business_info")
private BusinessInfo businessInfo;
/**
* 公众号授权给开发者的权限集列表ID为1到15时分别代表 消息管理权限 用户管理权限 帐号服务权限 网页服务权限 微信小店权限 微信多客服权限
* 群发与通知权限 微信卡券权限 微信扫一扫权限 微信连WIFI权限 素材管理权限 微信摇周边权限 微信门店权限 微信支付权限 自定义菜单权限
*/
@JSONField(deserialize = false)
private List<Integer> privileges;
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getHeadImg() {
return headImg;
}
public void setHeadImg(String headImg) {
this.headImg = headImg;
}
public int getServiceType() {
return serviceType;
}
public void setServiceType(int serviceType) {
this.serviceType = serviceType;
}
public int getVerifyType() {
return verifyType;
}
public void setVerifyType(int verifyType) {
this.verifyType = verifyType;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public String getQrcodeUrl() {
return qrcodeUrl;
}
public void setQrcodeUrl(String qrcodeUrl) {
this.qrcodeUrl = qrcodeUrl;
}
public BusinessInfo getBusinessInfo() {
return businessInfo;
}
public void setBusinessInfo(BusinessInfo businessInfo) {
this.businessInfo = businessInfo;
}
public List<Integer> getPrivileges() {
return privileges;
}
public void setPrivileges(List<Integer> privileges) {
this.privileges = privileges;
}
@Override
public String toString() {
return "ComponentAuthInfo [nickName=" + nickName + ", headImg="
+ headImg + ", serviceType=" + serviceType + ", verifyType="
+ verifyType + ", userName=" + userName + ", alias=" + alias
+ ", qrcodeUrl=" + qrcodeUrl + ", businessInfo=" + businessInfo
+ ", privileges=" + privileges + "]";
}
public static class BusinessInfo implements Serializable {
private static final long serialVersionUID = 3106626182191149662L;
/**
* 是否开通微信门店功能
*/
@JSONField(name = "open_store")
private boolean openStore;
/**
* 是否开通微信扫商品功能
*/
@JSONField(name = "open_scan")
private boolean openScan;
/**
* 是否开通微信支付功能
*/
@JSONField(name = "open_pay")
private boolean openPay;
/**
* 是否开通微信卡券功能
*/
@JSONField(name = "open_card")
private boolean openCard;
/**
* 是否开通微信摇一摇功能
*/
@JSONField(name = "open_shake")
private boolean openShake;
public boolean isOpenStore() {
return openStore;
}
public void setOpenStore(boolean openStore) {
this.openStore = openStore;
}
public boolean isOpenScan() {
return openScan;
}
public void setOpenScan(boolean openScan) {
this.openScan = openScan;
}
public boolean isOpenPay() {
return openPay;
}
public void setOpenPay(boolean openPay) {
this.openPay = openPay;
}
public boolean isOpenCard() {
return openCard;
}
public void setOpenCard(boolean openCard) {
this.openCard = openCard;
}
public boolean isOpenShake() {
return openShake;
}
public void setOpenShake(boolean openShake) {
this.openShake = openShake;
}
@Override
public String toString() {
return "BusinessInfo [openStore=" + openStore + ", openScan="
+ openScan + ", openPay=" + openPay + ", openCard="
+ openCard + ", openShake=" + openShake + "]";
}
}
}

View File

@ -14,18 +14,26 @@ public final class URLConsts {
/** /**
* 公众平台获取token的url * 公众平台获取token的url
*/ */
public static final String ASSESS_TOKEN_URL = BASE_URL + "/token?grant_type=client_credential&appid=%s&secret=%s"; public static final String ASSESS_TOKEN_URL = BASE_URL
+ "/token?grant_type=client_credential&appid=%s&secret=%s";
/** /**
* 公众平台jssdk获取token的url * 公众平台jssdk获取token的url
*/ */
public static final String JS_TICKET_URL = BASE_URL + "/ticket/getticket?access_token=%s&type=%s"; public static final String JS_TICKET_URL = BASE_URL
+ "/ticket/getticket?access_token=%s&type=%s";
/** /**
* 平台获取token的url * 平台获取token的url
*/ */
public static final String COMPONENT_TOKEN_URL = BASE_URL + "/component/api_component_token"; public static final String COMPONENT_TOKEN_URL = BASE_URL
+ "/component/api_component_token";
/** /**
* 平台获取预授权码的url * 平台获取预授权码的url
*/ */
public static final String COMPONENET_PRE_CODE_URL = BASE_URL public static final String COMPONENET_PRE_CODE_URL = BASE_URL
+ "/component/api_create_preauthcode?component_access_token=%s"; + "/component/api_create_preauthcode?component_access_token=%s";
/**
* 开放平台获取公众号access_token的url
*/
public static final String TOKEN_COMPONENT_URL = BASE_URL
+ "/component/api_authorizer_token?component_access_token=%s";
} }

View File

@ -38,7 +38,6 @@ import com.foxinmy.weixin4j.qy.model.IdParameter;
import com.foxinmy.weixin4j.qy.model.Party; import com.foxinmy.weixin4j.qy.model.Party;
import com.foxinmy.weixin4j.qy.model.Tag; import com.foxinmy.weixin4j.qy.model.Tag;
import com.foxinmy.weixin4j.qy.model.User; import com.foxinmy.weixin4j.qy.model.User;
import com.foxinmy.weixin4j.qy.suite.SuitePerCodeManager;
import com.foxinmy.weixin4j.qy.suite.WeixinTokenSuiteCreator; import com.foxinmy.weixin4j.qy.suite.WeixinTokenSuiteCreator;
import com.foxinmy.weixin4j.qy.token.WeixinTicketCreator; import com.foxinmy.weixin4j.qy.token.WeixinTicketCreator;
import com.foxinmy.weixin4j.qy.token.WeixinTokenCreator; import com.foxinmy.weixin4j.qy.token.WeixinTokenCreator;
@ -47,6 +46,7 @@ import com.foxinmy.weixin4j.qy.type.InviteType;
import com.foxinmy.weixin4j.qy.type.KfType; import com.foxinmy.weixin4j.qy.type.KfType;
import com.foxinmy.weixin4j.qy.type.UserStatus; import com.foxinmy.weixin4j.qy.type.UserStatus;
import com.foxinmy.weixin4j.setting.Weixin4jSettings; import com.foxinmy.weixin4j.setting.Weixin4jSettings;
import com.foxinmy.weixin4j.token.PerTicketManager;
import com.foxinmy.weixin4j.token.TokenManager; import com.foxinmy.weixin4j.token.TokenManager;
import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.tuple.MpArticle;
import com.foxinmy.weixin4j.type.MediaType; import com.foxinmy.weixin4j.type.MediaType;
@ -137,21 +137,21 @@ public class WeixinProxy {
/** /**
* 第三方套件(永久授权码机制) * 第三方套件(永久授权码机制)
* *
* @param perCodeManager * @param perTicketManager
* 第三方套件永久授权码 * 第三方套件永久授权码
* {@link com.foxinmy.weixin4j.qy.api.SuiteApi#getPerCodeManager(String)} * {@link com.foxinmy.weixin4j.qy.api.SuiteApi#getPerCodeManager(String)}
* @param perTokenManager * @param suiteTokenManager
* 第三方套件凭证token * 第三方套件凭证token
* {@link com.foxinmy.weixin4j.qy.api.SuiteApi#getPerTokenManager(String)} * {@link com.foxinmy.weixin4j.qy.api.SuiteApi#getTokenManager}
* @see com.foxinmy.weixin4j.qy.api.SuiteApi * @see com.foxinmy.weixin4j.qy.api.SuiteApi
* @see WeixinSuiteProxy#getWeixinProxy(String, String) * @see WeixinSuiteProxy#getWeixinProxy(String, String)
*/ */
public WeixinProxy(SuitePerCodeManager perCodeManager, public WeixinProxy(PerTicketManager perTicketManager,
TokenManager perTokenManager) { TokenManager suiteTokenManager) {
this(new TokenManager(new WeixinTokenSuiteCreator(perCodeManager, this(new TokenManager(new WeixinTokenSuiteCreator(perTicketManager,
perTokenManager), perCodeManager.getCacheStorager())); suiteTokenManager), perTicketManager.getCacheStorager()));
this.settings = new Weixin4jSettings<WeixinAccount>(new WeixinAccount( this.settings = new Weixin4jSettings<WeixinAccount>(new WeixinAccount(
perCodeManager.getAuthCorpId(), null)); perTicketManager.getAuthAppId(), null));
} }
/** /**

View File

@ -9,6 +9,7 @@ import java.util.Map;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Consts; import com.foxinmy.weixin4j.model.Consts;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.qy.api.ProviderApi; import com.foxinmy.weixin4j.qy.api.ProviderApi;
import com.foxinmy.weixin4j.qy.api.SuiteApi; import com.foxinmy.weixin4j.qy.api.SuiteApi;
@ -54,8 +55,8 @@ public class WeixinSuiteProxy {
* 默认使用文件方式保存token使用weixin4j.properties配置的账号信息 * 默认使用文件方式保存token使用weixin4j.properties配置的账号信息
*/ */
public WeixinSuiteProxy() { public WeixinSuiteProxy() {
this(new Weixin4jSettings<WeixinQyAccount>( this(new Weixin4jSettings<WeixinQyAccount>(JSON.parseObject(
JSON.parseObject(Weixin4jConfigUtil.getValue("account"), WeixinQyAccount.class))); Weixin4jConfigUtil.getValue("account"), WeixinQyAccount.class)));
} }
/** /**
@ -70,15 +71,18 @@ public class WeixinSuiteProxy {
this.suiteMap = new HashMap<String, SuiteApi>(suites.size()); this.suiteMap = new HashMap<String, SuiteApi>(suites.size());
for (WeixinAccount suite : suites) { for (WeixinAccount suite : suites) {
this.suiteMap.put(suite.getId(), new SuiteApi( this.suiteMap.put(suite.getId(), new SuiteApi(
new TicketManager(suite.getId(), suite.getSecret(), settings.getCacheStorager0()))); new TicketManager(suite.getId(), suite.getSecret(),
settings.getCacheStorager0())));
} }
this.suiteMap.put(null, suiteMap.get(suites.get(0).getId())); this.suiteMap.put(null, suiteMap.get(suites.get(0).getId()));
} }
if (StringUtil.isNotBlank(settings.getAccount().getId()) if (StringUtil.isNotBlank(settings.getAccount().getId())
&& StringUtil.isNotBlank(settings.getAccount().getProviderSecret())) { && StringUtil.isNotBlank(settings.getAccount()
.getProviderSecret())) {
this.providerApi = new ProviderApi( this.providerApi = new ProviderApi(
new TokenManager(new WeixinProviderTokenCreator(settings.getAccount().getId(), new TokenManager(new WeixinProviderTokenCreator(settings
settings.getAccount().getProviderSecret()), settings.getCacheStorager0()), .getAccount().getId(), settings.getAccount()
.getProviderSecret()), settings.getCacheStorager0()),
settings.getCacheStorager0()); settings.getCacheStorager0());
} }
} }
@ -114,6 +118,24 @@ public class WeixinSuiteProxy {
return this.suiteMap.get(suiteId); return this.suiteMap.get(suiteId);
} }
/**
* 获取套件的预授权码
*
* @param suiteId
* 套件ID
* @return 预授权码
* @see com.foxinmy.weixin4j.qy.api.SuiteApi
* @see com.foxinmy.weixin4j.qy.api.SuiteApi#getPreCodeManager()
* @throws WeixinException
*/
public String preSuiteTicket(String suiteId) throws WeixinException {
Token token = suite(suiteId).getTicketManager().getTicket();
if (token == null || StringUtil.isBlank(token.getAccessToken())) {
throw new WeixinException("maybe oauth first?");
}
return token.getAccessToken();
}
/** /**
* 缓存套件ticket(多个套件 * 缓存套件ticket(多个套件
* *
@ -126,7 +148,8 @@ public class WeixinSuiteProxy {
* 推送suite_ticket协议</a> * 推送suite_ticket协议</a>
* @throws WeixinException * @throws WeixinException
*/ */
public void cacheTicket(String suiteId, String suiteTicket) throws WeixinException { public void cacheTicket(String suiteId, String suiteTicket)
throws WeixinException {
suite(suiteId).getTicketManager().cachingTicket(suiteTicket); suite(suiteId).getTicketManager().cachingTicket(suiteTicket);
} }
@ -141,7 +164,8 @@ public class WeixinSuiteProxy {
* @throws WeixinException * @throws WeixinException
*/ */
public String getSuiteAuthorizeURL(String suiteId) throws WeixinException { public String getSuiteAuthorizeURL(String suiteId) throws WeixinException {
String redirectUri = Weixin4jConfigUtil.getValue("suite.oauth.redirect.uri"); String redirectUri = Weixin4jConfigUtil
.getValue("suite.oauth.redirect.uri");
return getSuiteAuthorizeURL(suiteId, redirectUri, "state"); return getSuiteAuthorizeURL(suiteId, redirectUri, "state");
} }
@ -161,9 +185,11 @@ public class WeixinSuiteProxy {
* @return 请求授权的URL * @return 请求授权的URL
* @throws WeixinException * @throws WeixinException
*/ */
public String getSuiteAuthorizeURL(String suiteId, String redirectUri, String state) throws WeixinException { public String getSuiteAuthorizeURL(String suiteId, String redirectUri,
String state) throws WeixinException {
try { try {
return String.format(URLConsts.SUITE_OAUTH_URL, suiteId, suite(suiteId).getTicketManager().getTicket(), return String.format(URLConsts.SUITE_OAUTH_URL, suiteId,
suite(suiteId).getTicketManager().getTicket(),
URLEncoder.encode(redirectUri, Consts.UTF_8.name()), state); URLEncoder.encode(redirectUri, Consts.UTF_8.name()), state);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
; ;
@ -205,7 +231,8 @@ public class WeixinSuiteProxy {
* 获取登录企业号官网的url</a> * 获取登录企业号官网的url</a>
* @throws WeixinException * @throws WeixinException
*/ */
public String getLoginUrl(String corpId, LoginTargetType targetType, int agentId) throws WeixinException { public String getLoginUrl(String corpId, LoginTargetType targetType,
int agentId) throws WeixinException {
return providerApi.getLoginUrl(corpId, targetType, agentId); return providerApi.getLoginUrl(corpId, targetType, agentId);
} }
@ -220,8 +247,8 @@ public class WeixinSuiteProxy {
* @return * @return
*/ */
public WeixinProxy getWeixinProxy(String suiteId, String authCorpId) { public WeixinProxy getWeixinProxy(String suiteId, String authCorpId) {
return new WeixinProxy(suite(suiteId).getPerCodeManager(authCorpId), return new WeixinProxy(suite(suiteId).getPerTicketManager(authCorpId),
suite(suiteId).getPerTokenManager(authCorpId)); suite(suiteId).getTokenManager());
} }
public final static String VERSION = "1.7.0"; public final static String VERSION = "1.7.0";

View File

@ -10,10 +10,10 @@ import com.foxinmy.weixin4j.qy.model.AgentInfo;
import com.foxinmy.weixin4j.qy.model.AgentSetter; import com.foxinmy.weixin4j.qy.model.AgentSetter;
import com.foxinmy.weixin4j.qy.model.OUserInfo; import com.foxinmy.weixin4j.qy.model.OUserInfo;
import com.foxinmy.weixin4j.qy.model.User; import com.foxinmy.weixin4j.qy.model.User;
import com.foxinmy.weixin4j.qy.suite.SuitePerCodeManager;
import com.foxinmy.weixin4j.qy.suite.WeixinSuitePreCodeCreator; import com.foxinmy.weixin4j.qy.suite.WeixinSuitePreCodeCreator;
import com.foxinmy.weixin4j.qy.suite.WeixinSuiteTokenCreator; import com.foxinmy.weixin4j.qy.suite.WeixinSuiteTokenCreator;
import com.foxinmy.weixin4j.qy.suite.WeixinTokenSuiteCreator; import com.foxinmy.weixin4j.qy.suite.WeixinTokenSuiteCreator;
import com.foxinmy.weixin4j.token.PerTicketManager;
import com.foxinmy.weixin4j.token.TicketManager; import com.foxinmy.weixin4j.token.TicketManager;
import com.foxinmy.weixin4j.token.TokenCreator; import com.foxinmy.weixin4j.token.TokenCreator;
import com.foxinmy.weixin4j.token.TokenManager; import com.foxinmy.weixin4j.token.TokenManager;
@ -51,9 +51,8 @@ public class SuiteApi extends QyApi {
this.ticketManager = ticketManager; this.ticketManager = ticketManager;
this.tokenManager = new TokenManager(new WeixinSuiteTokenCreator( this.tokenManager = new TokenManager(new WeixinSuiteTokenCreator(
ticketManager), ticketManager.getCacheStorager()); ticketManager), ticketManager.getCacheStorager());
this.preCodeManager = new TokenManager( this.preCodeManager = new TokenManager(new WeixinSuitePreCodeCreator(
new WeixinSuitePreCodeCreator(tokenManager, tokenManager, ticketManager.getThirdId()),
ticketManager.getId()),
ticketManager.getCacheStorager()); ticketManager.getCacheStorager());
} }
@ -91,9 +90,9 @@ public class SuiteApi extends QyApi {
* 授权方corpid * 授权方corpid
* @return * @return
*/ */
public SuitePerCodeManager getPerCodeManager(String authCorpId) { public PerTicketManager getPerTicketManager(String authCorpId) {
return new SuitePerCodeManager(authCorpId, return new PerTicketManager(authCorpId, ticketManager.getThirdId(),
ticketManager.getId(), ticketManager.getThirdSecret(),
ticketManager.getCacheStorager()); ticketManager.getCacheStorager());
} }
@ -106,7 +105,7 @@ public class SuiteApi extends QyApi {
*/ */
public TokenManager getPerTokenManager(String authCorpId) { public TokenManager getPerTokenManager(String authCorpId) {
return new TokenManager(new WeixinTokenSuiteCreator( return new TokenManager(new WeixinTokenSuiteCreator(
getPerCodeManager(authCorpId), tokenManager), getPerTicketManager(authCorpId), tokenManager),
ticketManager.getCacheStorager()); ticketManager.getCacheStorager());
} }
@ -130,8 +129,7 @@ public class SuiteApi extends QyApi {
para.put("session_info", appid); para.put("session_info", appid);
WeixinResponse response = weixinExecutor.post( WeixinResponse response = weixinExecutor.post(
String.format(suite_set_session_uri, String.format(suite_set_session_uri,
tokenManager.getAccessToken()), tokenManager.getAccessToken()), para.toJSONString());
para.toJSONString());
return response.getAsJsonResult(); return response.getAsJsonResult();
} }
@ -151,28 +149,26 @@ public class SuiteApi extends QyApi {
throws WeixinException { throws WeixinException {
String suite_get_permanent_uri = getRequestUri("suite_get_permanent_uri"); String suite_get_permanent_uri = getRequestUri("suite_get_permanent_uri");
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("suite_id", ticketManager.getId()); obj.put("suite_id", ticketManager.getThirdId());
obj.put("auth_code", authCode); obj.put("auth_code", authCode);
WeixinResponse response = weixinExecutor WeixinResponse response = weixinExecutor.post(
.post(String.format(suite_get_permanent_uri, String.format(suite_get_permanent_uri,
tokenManager.getAccessToken()), obj.toJSONString()); tokenManager.getAccessToken()), obj.toJSONString());
obj = response.getAsJson(); obj = response.getAsJson();
obj.put("corp_info", obj.remove("auth_corp_info")); obj.put("corp_info", obj.remove("auth_corp_info"));
obj.put("user_info", obj.remove("auth_user_info")); obj.put("user_info", obj.remove("auth_user_info"));
OUserInfo oInfo = JSON.toJavaObject(obj, OUserInfo.class); OUserInfo oInfo = JSON.toJavaObject(obj, OUserInfo.class);
// 微信授权企业号的永久授权码 // 微信授权企业号的永久授权码
SuitePerCodeManager suitePerCodeManager = getPerCodeManager(oInfo PerTicketManager perTicketManager = getPerTicketManager(oInfo
.getCorpInfo().getCorpId()); .getCorpInfo().getCorpId());
// 缓存微信企业号access_token // 缓存微信企业号access_token
TokenCreator tokenCreator = new WeixinTokenSuiteCreator( TokenCreator tokenCreator = new WeixinTokenSuiteCreator(
suitePerCodeManager, tokenManager); perTicketManager, tokenManager);
Token token = new Token(obj.getString("access_token"), Token token = new Token(obj.getString("access_token"),
obj.getLongValue("expires_in") * 1000l); obj.getLongValue("expires_in") * 1000l);
ticketManager.getCacheStorager() ticketManager.getCacheStorager().caching(tokenCreator.key(), token);
.caching(tokenCreator.key(), token); // 缓存微信企业号的永久授权码
// 缓存微信企业号永久授权码 perTicketManager.cachingTicket(obj.getString("permanent_code"));
suitePerCodeManager.cachingPermanentCode(obj
.getString("permanent_code"));
return oInfo; return oInfo;
} }
@ -190,12 +186,11 @@ public class SuiteApi extends QyApi {
public OUserInfo getOAuthInfo(String authCorpId) throws WeixinException { public OUserInfo getOAuthInfo(String authCorpId) throws WeixinException {
String suite_get_authinfo_uri = getRequestUri("suite_get_authinfo_uri"); String suite_get_authinfo_uri = getRequestUri("suite_get_authinfo_uri");
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("suite_id", ticketManager.getId()); obj.put("suite_id", ticketManager.getThirdId());
obj.put("auth_corpid", authCorpId); obj.put("auth_corpid", authCorpId);
obj.put("permanent_code", getPerCodeManager(authCorpId) obj.put("permanent_code", getPerTicketManager(authCorpId).getAccessTicket());
.getPermanentCode()); WeixinResponse response = weixinExecutor.post(
WeixinResponse response = weixinExecutor String.format(suite_get_authinfo_uri,
.post(String.format(suite_get_authinfo_uri,
tokenManager.getAccessToken()), obj.toJSONString()); tokenManager.getAccessToken()), obj.toJSONString());
obj = response.getAsJson(); obj = response.getAsJson();
obj.put("corp_info", obj.remove("auth_corp_info")); obj.put("corp_info", obj.remove("auth_corp_info"));
@ -220,13 +215,12 @@ public class SuiteApi extends QyApi {
throws WeixinException { throws WeixinException {
String suite_get_agent_uri = getRequestUri("suite_get_agent_uri"); String suite_get_agent_uri = getRequestUri("suite_get_agent_uri");
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("suite_id", ticketManager.getId()); obj.put("suite_id", ticketManager.getThirdId());
obj.put("auth_corpid", authCorpId); obj.put("auth_corpid", authCorpId);
obj.put("permanent_code", getPerCodeManager(authCorpId) obj.put("permanent_code", getPerTicketManager(authCorpId).getAccessTicket());
.getPermanentCode());
obj.put("agentid", agentid); obj.put("agentid", agentid);
WeixinResponse response = weixinExecutor WeixinResponse response = weixinExecutor.post(
.post(String.format(suite_get_agent_uri, String.format(suite_get_agent_uri,
tokenManager.getAccessToken()), obj.toJSONString()); tokenManager.getAccessToken()), obj.toJSONString());
JSONObject jsonObj = response.getAsJson(); JSONObject jsonObj = response.getAsJson();
AgentInfo agent = JSON.toJavaObject(jsonObj, AgentInfo.class); AgentInfo agent = JSON.toJavaObject(jsonObj, AgentInfo.class);
@ -258,10 +252,9 @@ public class SuiteApi extends QyApi {
throws WeixinException { throws WeixinException {
String suite_set_agent_uri = getRequestUri("suite_set_agent_uri"); String suite_set_agent_uri = getRequestUri("suite_set_agent_uri");
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("suite_id", ticketManager.getId()); obj.put("suite_id", ticketManager.getThirdId());
obj.put("auth_corpid", authCorpId); obj.put("auth_corpid", authCorpId);
obj.put("permanent_code", getPerCodeManager(authCorpId) obj.put("permanent_code", getPerTicketManager(authCorpId).getAccessTicket());
.getPermanentCode());
obj.put("agent", agentSet); obj.put("agent", agentSet);
WeixinResponse response = weixinExecutor.post( WeixinResponse response = weixinExecutor.post(
String.format(suite_set_agent_uri, String.format(suite_set_agent_uri,

View File

@ -1,73 +0,0 @@
package com.foxinmy.weixin4j.qy.suite;
import com.foxinmy.weixin4j.cache.CacheStorager;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.token.TokenCreator;
/**
* 应用套件永久授权码的存取
*
* @className SuitePerCodeManager
* @author jinyu(foxinmy@gmail.com)
* @date 2015年6月22日
* @since JDK 1.6
* @see
*/
public class SuitePerCodeManager {
private final String authCorpId;
private final String suiteId;
private final CacheStorager<Token> cacheStorager;
public SuitePerCodeManager(String authCorpId, String suiteId,
CacheStorager<Token> cacheStorager) {
this.authCorpId = authCorpId;
this.suiteId = suiteId;
this.cacheStorager = cacheStorager;
}
/**
* 缓存永久授权码
*
* @param permanentCode
* @throws WeixinException
*/
public void cachingPermanentCode(String permanentCode)
throws WeixinException {
Token token = new Token(permanentCode);
cacheStorager.caching(getCacheKey(), token);
}
/**
* 获取永久授权码的key
*
* @return
*/
public String getCacheKey() {
return String.format("%sqy_suite_percode_%s_%s",
TokenCreator.CACHEKEY_PREFIX, suiteId, authCorpId);
}
/**
* 查找永久授权码
*
* @return
* @throws WeixinException
*/
public String getPermanentCode() throws WeixinException {
return cacheStorager.lookup(getCacheKey()).getAccessToken();
}
public String getSuiteId() {
return this.suiteId;
}
public String getAuthCorpId() {
return this.authCorpId;
}
public CacheStorager<Token> getCacheStorager() {
return this.cacheStorager;
}
}

View File

@ -34,15 +34,15 @@ public class WeixinSuiteTokenCreator extends TokenCreator {
@Override @Override
public String key0() { public String key0() {
return String.format("qy_suite_token_%s", ticketManager.getId()); return String.format("qy_suite_token_%s", ticketManager.getThirdId());
} }
@Override @Override
public Token create() throws WeixinException { public Token create() throws WeixinException {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("suite_id", ticketManager.getId()); obj.put("suite_id", ticketManager.getThirdId());
obj.put("suite_secret", ticketManager.getSecret()); obj.put("suite_secret", ticketManager.getThirdSecret());
obj.put("suite_ticket", ticketManager.getTicket()); obj.put("suite_ticket", ticketManager.getAccessTicket());
WeixinResponse response = weixinExecutor.post( WeixinResponse response = weixinExecutor.post(
URLConsts.SUITE_TOKEN_URL, obj.toJSONString()); URLConsts.SUITE_TOKEN_URL, obj.toJSONString());
obj = response.getAsJson(); obj = response.getAsJson();

View File

@ -5,6 +5,7 @@ import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.qy.type.URLConsts; import com.foxinmy.weixin4j.qy.type.URLConsts;
import com.foxinmy.weixin4j.token.PerTicketManager;
import com.foxinmy.weixin4j.token.TokenCreator; import com.foxinmy.weixin4j.token.TokenCreator;
import com.foxinmy.weixin4j.token.TokenManager; import com.foxinmy.weixin4j.token.TokenManager;
@ -22,36 +23,36 @@ import com.foxinmy.weixin4j.token.TokenManager;
*/ */
public class WeixinTokenSuiteCreator extends TokenCreator { public class WeixinTokenSuiteCreator extends TokenCreator {
private final SuitePerCodeManager perCodeManager; private final PerTicketManager perTicketManager;
private final TokenManager suiteTokenManager; private final TokenManager suiteTokenManager;
/** /**
* *
* @param perCodeManager * @param perTicketManager
* 第三方套件永久授权码 * 第三方套件永久授权码
* @param suitetokenManager * @param suiteTokenManager
* 第三方套件凭证token * 第三方套件凭证token
*/ */
public WeixinTokenSuiteCreator(SuitePerCodeManager perCodeManager, public WeixinTokenSuiteCreator(PerTicketManager perTicketManager,
TokenManager suiteTokenManager) { TokenManager suiteTokenManager) {
this.perCodeManager = perCodeManager; this.perTicketManager = perTicketManager;
this.suiteTokenManager = suiteTokenManager; this.suiteTokenManager = suiteTokenManager;
} }
@Override @Override
public String key0() { public String key0() {
return String.format("qy_token_suite_%s_%s", return String.format("qy_token_suite_%s_%s",
perCodeManager.getSuiteId(), perCodeManager.getAuthCorpId()); perTicketManager.getThirdId(), perTicketManager.getAuthAppId());
} }
@Override @Override
public Token create() throws WeixinException { public Token create() throws WeixinException {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("suite_id", perCodeManager.getSuiteId()); obj.put("suite_id", perTicketManager.getThirdId());
obj.put("auth_corpid", perCodeManager.getAuthCorpId()); obj.put("auth_corpid", perTicketManager.getAuthAppId());
obj.put("permanent_code", perCodeManager.getPermanentCode()); obj.put("permanent_code", perTicketManager.getAccessTicket());
WeixinResponse response = weixinExecutor WeixinResponse response = weixinExecutor.post(
.post(String.format(URLConsts.TOKEN_SUITE_URL, String.format(URLConsts.TOKEN_SUITE_URL,
suiteTokenManager.getAccessToken()), obj.toJSONString()); suiteTokenManager.getAccessToken()), obj.toJSONString());
obj = response.getAsJson(); obj = response.getAsJson();
return new Token(obj.getString("access_token"), return new Token(obj.getString("access_token"),