| @@ -1,20 +1,25 @@ | |||||
| package me.chanjar.weixin.cp.api; | package me.chanjar.weixin.cp.api; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo; | |||||
| import me.chanjar.weixin.cp.bean.WxCpUserDetail; | import me.chanjar.weixin.cp.bean.WxCpUserDetail; | ||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * OAuth2相关管理接口 | |||||
| * OAuth2相关管理接口. | |||||
| * Created by BinaryWang on 2017/6/24. | * Created by BinaryWang on 2017/6/24. | ||||
| * </pre> | * </pre> | ||||
| * | * | ||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| */ | */ | ||||
| public interface WxCpOAuth2Service { | public interface WxCpOAuth2Service { | ||||
| String URL_GET_USER_INFO = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?code=%s&agentid=%d"; | |||||
| String URL_GET_USER_DETAIL = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail"; | |||||
| String URL_OAUTH_2_AUTHORIZE = "https://open.weixin.qq.com/connect/oauth2/authorize"; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 构造oauth2授权的url连接 | |||||
| * 构造oauth2授权的url连接. | |||||
| * </pre> | * </pre> | ||||
| * | * | ||||
| * @param state 状态码 | * @param state 状态码 | ||||
| @@ -24,7 +29,7 @@ public interface WxCpOAuth2Service { | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 构造oauth2授权的url连接 | |||||
| * 构造oauth2授权的url连接. | |||||
| * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=企业获取code | * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=企业获取code | ||||
| * </pre> | * </pre> | ||||
| * | * | ||||
| @@ -57,16 +62,18 @@ public interface WxCpOAuth2Service { | |||||
| * </pre> | * </pre> | ||||
| * | * | ||||
| * @param code 微信oauth授权返回的代码 | * @param code 微信oauth授权返回的代码 | ||||
| * @return [userid, deviceid] | |||||
| * @return WxCpOauth2UserInfo | |||||
| * @throws WxErrorException 异常 | |||||
| * @see #getUserInfo(Integer, String) | * @see #getUserInfo(Integer, String) | ||||
| */ | */ | ||||
| String[] getUserInfo(String code) throws WxErrorException; | |||||
| WxCpOauth2UserInfo getUserInfo(String code) throws WxErrorException; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 根据code获取成员信息 | * 根据code获取成员信息 | ||||
| * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息 | * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息 | ||||
| * https://work.weixin.qq.com/api/doc#10028/根据code获取成员信息 | * https://work.weixin.qq.com/api/doc#10028/根据code获取成员信息 | ||||
| * https://work.weixin.qq.com/api/doc#90000/90135/91023 获取访问用户身份 | |||||
| * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。 | * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。 | ||||
| * | * | ||||
| * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出 | * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出 | ||||
| @@ -74,10 +81,11 @@ public interface WxCpOAuth2Service { | |||||
| * | * | ||||
| * @param agentId 企业号应用的id | * @param agentId 企业号应用的id | ||||
| * @param code 通过成员授权获取到的code,最大为512字节。每次成员授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。 | * @param code 通过成员授权获取到的code,最大为512字节。每次成员授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。 | ||||
| * @return [UserId, DeviceId, OpenId, user_ticket, expires_in] | |||||
| * @return WxCpOauth2UserInfo | |||||
| * @throws WxErrorException 异常 | |||||
| * @see #getUserInfo(String) | * @see #getUserInfo(String) | ||||
| */ | */ | ||||
| String[] getUserInfo(Integer agentId, String code) throws WxErrorException; | |||||
| WxCpOauth2UserInfo getUserInfo(Integer agentId, String code) throws WxErrorException; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| @@ -92,6 +100,8 @@ public interface WxCpOAuth2Service { | |||||
| * </pre> | * </pre> | ||||
| * | * | ||||
| * @param userTicket 成员票据 | * @param userTicket 成员票据 | ||||
| * @return WxCpUserDetail | |||||
| * @throws WxErrorException 异常 | |||||
| */ | */ | ||||
| WxCpUserDetail getUserDetail(String userTicket) throws WxErrorException; | WxCpUserDetail getUserDetail(String userTicket) throws WxErrorException; | ||||
| } | } | ||||
| @@ -3,30 +3,31 @@ package me.chanjar.weixin.cp.api.impl; | |||||
| import com.google.gson.JsonElement; | import com.google.gson.JsonElement; | ||||
| import com.google.gson.JsonObject; | import com.google.gson.JsonObject; | ||||
| import com.google.gson.JsonParser; | import com.google.gson.JsonParser; | ||||
| import lombok.AllArgsConstructor; | |||||
| import me.chanjar.weixin.common.api.WxConsts; | import me.chanjar.weixin.common.api.WxConsts; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.common.util.http.URIUtil; | import me.chanjar.weixin.common.util.http.URIUtil; | ||||
| import me.chanjar.weixin.common.util.json.GsonHelper; | import me.chanjar.weixin.common.util.json.GsonHelper; | ||||
| import me.chanjar.weixin.cp.api.WxCpOAuth2Service; | import me.chanjar.weixin.cp.api.WxCpOAuth2Service; | ||||
| import me.chanjar.weixin.cp.api.WxCpService; | import me.chanjar.weixin.cp.api.WxCpService; | ||||
| import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo; | |||||
| import me.chanjar.weixin.cp.bean.WxCpUserDetail; | import me.chanjar.weixin.cp.bean.WxCpUserDetail; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
| import static me.chanjar.weixin.common.api.WxConsts.OAuth2Scope.SNSAPI_PRIVATEINFO; | |||||
| import static me.chanjar.weixin.common.api.WxConsts.OAuth2Scope.SNSAPI_USERINFO; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * | |||||
| * oauth2相关接口实现类. | |||||
| * Created by Binary Wang on 2017-6-25. | * Created by Binary Wang on 2017-6-25. | ||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| * | |||||
| * @author Binary Wang | |||||
| * </pre> | * </pre> | ||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | */ | ||||
| @AllArgsConstructor | |||||
| public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service { | public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service { | ||||
| private WxCpService mainService; | |||||
| public WxCpOAuth2ServiceImpl(WxCpService mainService) { | |||||
| this.mainService = mainService; | |||||
| } | |||||
| private final WxCpService mainService; | |||||
| @Override | @Override | ||||
| public String buildAuthorizationUrl(String state) { | public String buildAuthorizationUrl(String state) { | ||||
| @@ -43,50 +44,49 @@ public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service { | |||||
| @Override | @Override | ||||
| public String buildAuthorizationUrl(String redirectUri, String state, String scope) { | public String buildAuthorizationUrl(String redirectUri, String state, String scope) { | ||||
| StringBuilder url = new StringBuilder("https://open.weixin.qq.com/connect/oauth2/authorize?"); | |||||
| url.append("appid=").append(this.mainService.getWxCpConfigStorage().getCorpId()); | |||||
| StringBuilder url = new StringBuilder(WxCpOAuth2Service.URL_OAUTH_2_AUTHORIZE); | |||||
| url.append("?appid=").append(this.mainService.getWxCpConfigStorage().getCorpId()); | |||||
| url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectUri)); | url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectUri)); | ||||
| url.append("&response_type=code"); | url.append("&response_type=code"); | ||||
| url.append("&scope=").append(scope); | url.append("&scope=").append(scope); | ||||
| if (WxConsts.OAuth2Scope.SNSAPI_PRIVATEINFO.equals(scope) | |||||
| || WxConsts.OAuth2Scope.SNSAPI_USERINFO.equals(scope)) { | |||||
| if (SNSAPI_PRIVATEINFO.equals(scope) || SNSAPI_USERINFO.equals(scope)) { | |||||
| url.append("&agentid=").append(this.mainService.getWxCpConfigStorage().getAgentId()); | url.append("&agentid=").append(this.mainService.getWxCpConfigStorage().getAgentId()); | ||||
| } | } | ||||
| if (state != null) { | if (state != null) { | ||||
| url.append("&state=").append(state); | url.append("&state=").append(state); | ||||
| } | } | ||||
| url.append("#wechat_redirect"); | url.append("#wechat_redirect"); | ||||
| return url.toString(); | return url.toString(); | ||||
| } | } | ||||
| @Override | @Override | ||||
| public String[] getUserInfo(String code) throws WxErrorException { | |||||
| public WxCpOauth2UserInfo getUserInfo(String code) throws WxErrorException { | |||||
| return this.getUserInfo(this.mainService.getWxCpConfigStorage().getAgentId(), code); | return this.getUserInfo(this.mainService.getWxCpConfigStorage().getAgentId(), code); | ||||
| } | } | ||||
| @Override | @Override | ||||
| public String[] getUserInfo(Integer agentId, String code) throws WxErrorException { | |||||
| String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?code=%s&agentid=%d", | |||||
| code, agentId); | |||||
| String responseText = this.mainService.get(url, null); | |||||
| public WxCpOauth2UserInfo getUserInfo(Integer agentId, String code) throws WxErrorException { | |||||
| String responseText = this.mainService.get(String.format(WxCpOAuth2Service.URL_GET_USER_INFO, code, agentId), null); | |||||
| JsonElement je = new JsonParser().parse(responseText); | JsonElement je = new JsonParser().parse(responseText); | ||||
| JsonObject jo = je.getAsJsonObject(); | JsonObject jo = je.getAsJsonObject(); | ||||
| return new String[]{GsonHelper.getString(jo, "UserId"), | |||||
| GsonHelper.getString(jo, "DeviceId"), | |||||
| GsonHelper.getString(jo, "OpenId"), | |||||
| GsonHelper.getString(jo, "user_ticket"), | |||||
| GsonHelper.getString(jo, "expires_in") | |||||
| }; | |||||
| return WxCpOauth2UserInfo.builder() | |||||
| .userId(GsonHelper.getString(jo, "UserId")) | |||||
| .deviceId(GsonHelper.getString(jo, "DeviceId")) | |||||
| .openId(GsonHelper.getString(jo, "OpenId")) | |||||
| .userTicket(GsonHelper.getString(jo, "user_ticket")) | |||||
| .expiresIn(GsonHelper.getString(jo, "expires_in")) | |||||
| .build(); | |||||
| } | } | ||||
| @Override | @Override | ||||
| public WxCpUserDetail getUserDetail(String userTicket) throws WxErrorException { | public WxCpUserDetail getUserDetail(String userTicket) throws WxErrorException { | ||||
| String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail"; | |||||
| JsonObject param = new JsonObject(); | JsonObject param = new JsonObject(); | ||||
| param.addProperty("user_ticket", userTicket); | param.addProperty("user_ticket", userTicket); | ||||
| String responseText = this.mainService.post(url, param.toString()); | |||||
| String responseText = this.mainService.post(WxCpOAuth2Service.URL_GET_USER_DETAIL, param.toString()); | |||||
| return WxCpGsonBuilder.create().fromJson(responseText, WxCpUserDetail.class); | return WxCpGsonBuilder.create().fromJson(responseText, WxCpUserDetail.class); | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,28 @@ | |||||
| package me.chanjar.weixin.cp.bean; | |||||
| import lombok.AllArgsConstructor; | |||||
| import lombok.Builder; | |||||
| import lombok.Data; | |||||
| import lombok.NoArgsConstructor; | |||||
| import lombok.experimental.Accessors; | |||||
| /** | |||||
| * <pre> | |||||
| * 用oauth2获取用户信息的结果类 | |||||
| * Created by BinaryWang on 2019/5/26. | |||||
| * </pre> | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| @Data | |||||
| @Accessors(chain = true) | |||||
| @NoArgsConstructor | |||||
| @AllArgsConstructor | |||||
| @Builder | |||||
| public class WxCpOauth2UserInfo { | |||||
| private String openId; | |||||
| private String deviceId; | |||||
| private String userId; | |||||
| private String userTicket; | |||||
| private String expiresIn; | |||||
| } | |||||
| @@ -4,10 +4,13 @@ import com.google.inject.Inject; | |||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.cp.api.ApiTestModule; | import me.chanjar.weixin.cp.api.ApiTestModule; | ||||
| import me.chanjar.weixin.cp.api.WxCpService; | import me.chanjar.weixin.cp.api.WxCpService; | ||||
| import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo; | |||||
| import me.chanjar.weixin.cp.bean.WxCpUserDetail; | import me.chanjar.weixin.cp.bean.WxCpUserDetail; | ||||
| import org.testng.annotations.Guice; | import org.testng.annotations.Guice; | ||||
| import org.testng.annotations.Test; | import org.testng.annotations.Test; | ||||
| import static org.assertj.core.api.Assertions.assertThat; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * Created by BinaryWang on 2018/4/22. | * Created by BinaryWang on 2018/4/22. | ||||
| @@ -28,6 +31,13 @@ public class WxCpOAuth2ServiceImplTest { | |||||
| @Test | @Test | ||||
| public void testGetUserInfo() throws WxErrorException { | public void testGetUserInfo() throws WxErrorException { | ||||
| this.wxService.getOauth2Service().getUserInfo("abc"); | |||||
| final WxCpOauth2UserInfo result = this.wxService.getOauth2Service().getUserInfo("abc"); | |||||
| assertThat(result).isNotNull(); | |||||
| System.out.println(result); | |||||
| } | } | ||||
| @Test | |||||
| public void testBuildAuthorizationUrl() { | |||||
| } | |||||
| } | } | ||||
| @@ -2,6 +2,7 @@ package me.chanjar.weixin.cp.demo; | |||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.cp.api.WxCpService; | import me.chanjar.weixin.cp.api.WxCpService; | ||||
| import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo; | |||||
| import javax.servlet.http.HttpServlet; | import javax.servlet.http.HttpServlet; | ||||
| import javax.servlet.http.HttpServletRequest; | import javax.servlet.http.HttpServletRequest; | ||||
| @@ -30,9 +31,9 @@ public class WxCpOAuth2Servlet extends HttpServlet { | |||||
| response.getWriter().println("<h1>code</h1>"); | response.getWriter().println("<h1>code</h1>"); | ||||
| response.getWriter().println(code); | response.getWriter().println(code); | ||||
| String[] res = this.wxCpService.getOauth2Service().getUserInfo(code); | |||||
| WxCpOauth2UserInfo res = this.wxCpService.getOauth2Service().getUserInfo(code); | |||||
| response.getWriter().println("<h1>result</h1>"); | response.getWriter().println("<h1>result</h1>"); | ||||
| response.getWriter().println(Arrays.toString(res)); | |||||
| response.getWriter().println(res); | |||||
| } catch (WxErrorException e) { | } catch (WxErrorException e) { | ||||
| e.printStackTrace(); | e.printStackTrace(); | ||||
| } | } | ||||