其他链接
目录
前言一
再次强调一下,我们这里的后台目前仅是为了验证企业微信三方开发的逻辑,所以并未分层。所有请求接收和业务处理都在controller中完成,数据也都存在配置文件data.properties中。也未做必要逻辑判断和排错处理,以尽量使代码简洁清晰。请知悉!
前言二
在上一篇文章中我们已经为企业安装好了应用并获取到了两个重要的参数:suite_ticket 和 auth_code。如果要通过应用获取授权企业的基本信息和使用企业微信的一些接口,我们需要先获得一些必要的 access_token。
access_token(访问凭证),顾名思义:是你访问企业微信后台的通行证。
微信的所有开发开发通常都是以获取token开始的。
企业微信三方开发要获取三种类型的access_token:
类型 | 说明 | 适用场景 |
---|---|---|
服务商的token | 以corpid(服务商CorpID)、provider_secret(服务商密钥)换取 provider_access_token,代表的是服务商的身份 | 用于服务商级别的接口调用,比如登录授权、推广二维码等 |
第三方应用的token | 以suite_id(第三方应用ID)、suite_secret(第三方应用密钥)、suite_ticket(后台定时推送)换取 suite_access_token,代表第三方应用的身份 | 用于获取第三方应用的预授权码,获取授权企业信息等。 |
授权企业的token | 企业安装第三方应用后,第三方服务商以企业的corpid、永久授权码来获取 access_token | 用于操作授权企业相关接口,如通讯录管理,消息推送等。 |
在此文中我们将依次获取这三个token。
同时安装应用还需要先授权配置,在第4小节即进行授权配置。
技术栈及工具
- 开发框架:spring-boot
- 开发工具: idea
获取TOKEN
上图是获取三个token所需的参数,首先是provider_access_token ,所需的两个参数都是在企业微信服务商后台获取。
其次是 suite_access_token,前两个参数也是在后台直接获取,而 suite_ticket 是微信后台每隔十分钟推送一次,我们通过 VerifyController 包中的 getSuiteToken 方法 获取,并保存到 data.properties 中(具体方法查看教程一)
最后是获取企业的 accesstoken,我们要先通过教程一的安装过程中已获取到的临时授权码 auth_code获取到永久授权码 permanent_code 和授权企业的 auth_corpid。
1、获取provider_access_token
新建一个TokenController:
package com.tan.cwp.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/token")
public class TokenController {
Logger logger = LoggerFactory.getLogger(TokenController.class);
}
其中新建一个方法 getProviderToken() 用于获取 provider_access_token(具体访问路径及参数说明查看官方文档):
/*
* 获取服务商凭证provider_access_token
*
* provider_access_token为接口访问凭证,有效期7200ms,需缓存
* 请求地址:https://qyapi.weixin.qq.com/cgi-bin/service/get_provider_token
* 请求方式: POST
* @parm1 服务商corpid
* @parm2 服务商provider_secret
*/
@RequestMapping(value = "p_token.do" ,method = RequestMethod.POST)
public void getProviderToken(HttpServletRequest request, HttpServletResponse response) throws JSONException, IOException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_provider_token";
JSONObject jsonParms = new JSONObject();
jsonParms.put("corpid", Constant.CorpID);
jsonParms.put("provider_secret", Constant.ProviderSecret);
//创建httpclient对象
CloseableHttpClient client = HttpClients.createDefault();
//创建post方式请求对象
HttpPost httpPost = new HttpPost(url);
//装填参数
StringEntity s = new StringEntity(jsonParms.toString(), "utf-8");
s.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,
"application/json"));
//设置参数到请求对象中
httpPost.setEntity(s);
System.out.println("请求地址:"+url);
//设置header信息
httpPost.setHeader("Content-type", "application/json");
httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
//执行请求操作,并拿到结果(同步阻塞)
CloseableHttpResponse httpresponse = client.execute(httpPost);
//获取结果实体
HttpEntity entity = httpresponse.getEntity();
JSONObject jsonObj = null;
if (entity != null) {
//按指定编码转换结果实体为String类型
String content = EntityUtils.toString(entity, "UTF-8");
System.out.println("doPost结果:"+content);
jsonObj = new JSONObject(content);
}
EntityUtils.consume(entity);
//释放链接
httpresponse.close();
// 将信息发送至前台
PrintWriter out = response.getWriter();
out.print(jsonObj);
out.close();
}
运行项目,并通过postman访问:
看后台打印:
获取成功!
注意,在做微信开发时,域名需要用内网穿透。如果提示IP不合法,请将对应IP加入 企业微信服务商后台>服务商信息>基本信息>IP白名单 中!
2、获取suite_access_token
同provider_access_token一样,这里还是要通过 httpclient对象 向微信指定的接口发送POST请求。我们可以建一个类专门处理发送http请求。
在Util包里新建个HttpHelper类:
package com.tan.cwp.util;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
public class HttpHelper {
public static JSONObject doGet(String url) {
System.out.println("doGet请求url:"+url);
// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
// 创建http GET请求
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = null;
JSONObject jsonObj = null;
try {
// 执行请求
response = httpclient.execute(httpGet);
//请求体内容
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println("doGet结果:"+content);
jsonObj = new JSONObject(content);
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObj;
}
public static JSONObject doPost(String url,JSONObject jsonParms) throws IOException, JSONException {
System.out.println("doPost请求url:"+url);
System.out.println("doPost请求Parm:"+jsonParms);
//创建httpclient对象
CloseableHttpClient client = HttpClients.createDefault();
//创建post方式请求对象
HttpPost httpPost = new HttpPost(url);
//装填参数
StringEntity s = new StringEntity(jsonParms.toString(), "utf-8");
s.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,
"application/json"));
//设置参数到请求对象中
httpPost.setEntity(s);
//设置header信息
httpPost.setHeader("Content-type", "application/json");
httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
//执行请求操作,并拿到结果(同步阻塞)
CloseableHttpResponse response = client.execute(httpPost);
//获取结果实体
HttpEntity entity = response.getEntity();
JSONObject jsonObj = null;
if (entity != null) {
//按指定编码转换结果实体为String类型
String content = EntityUtils.toString(entity, "UTF-8");
System.out.println("doPost结果:"+content);
jsonObj = new JSONObject(content);
}
EntityUtils.consume(entity);
//释放链接
response.close();
return jsonObj;
}
}
这下可以直接用这个包发送GET和POST请求。
回到 TokenController 新建一个 getSuiteToken() 方法:
/*
* 获取第三方应用凭证suite_access_token
*
* 请求地址: https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token
* 请求方式: POST
* @parm1 三方应用id suite_id
* @parm2 三方应用secret suite_secret
* @parm3 企业微信后台推送的ticket suite_ticket
*/
@RequestMapping(value = "s_token.do" ,method = RequestMethod.POST)
public void getSuiteToken(HttpServletRequest request, HttpServletResponse response) throws Exception {
String url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token";
String suite_ticket = PropertiesUtil.getProperty("suite_ticket");
JSONObject jsonParms = new JSONObject();
jsonParms.put("suite_id", Constant.SuiteID);
jsonParms.put("suite_secret", Constant.SuiteSecret);
jsonParms.put("suite_ticket", suite_ticket);
JSONObject jsonObj = HttpHelper.doPost(url,jsonParms);
PropertiesUtil.setProperty("suite_access_token", (String) jsonObj.get("suite_access_token"));
// 将信息发送至前台
PrintWriter out = response.getWriter();
out.print(jsonObj);
out.close();
}
再次运行项目,并通过postman访问:
后台成功打印出suite_acces_token:
3、获取企业access_token
以下3.1方法虽然也获取到了access_token,但它其实更重要的是获取一个重要变量——永久授权码permanent_code。这个变量是3.2方法获取access_token的重要参数!
3.1、获取企业永久授权码
注意这里的参数是 临时授权码auth_code ,是在安装应用成功时返回的。我们将其存在了 data.properties 中。而企业微信中还有个叫 预授权码pre_auth_code ,是用于第三方服务商安全验证的。请不要搞混!
新建一个方法 getPermanentcode() 用于获取永久授权码:
/*
* 获取企业永久授权码 permanent_code,及企业信息
* 请求地址: https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code?suite_access_token=SUITE_ACCESS_TOKEN
* 请求方式: POST
* @parm1 临时授权码auth_code,授权时返回
*/
@RequestMapping(value = "permanentcode.do" ,method = RequestMethod.POST)
public void getPermanentcode(HttpServletRequest request, HttpServletResponse response) throws JSONException, IOException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code?suite_access_token=";
String suite_access_token = PropertiesUtil.getProperty("suite_access_token");
url += suite_access_token;
String auth_code = PropertiesUtil.getProperty("auth_code");
JSONObject jsonParms = new JSONObject();
jsonParms.put("auth_code", auth_code);
JSONObject jsonObj = HttpHelper.doPost(url,jsonParms);
// 写入授权的所以信息
PropertiesUtil.setProperty("auth_company", jsonObj.toString());
//写入永久授权码
PropertiesUtil.setProperty("permanent_code", (String) jsonObj.get("permanent_code"));
JSONObject jsonObject_auth_corp_info = (JSONObject) jsonObj.get("auth_corp_info");
//写入授权企业id
PropertiesUtil.setProperty("auth_corpid", (String) jsonObject_auth_corp_info.get("corpid"));
// 将信息发送至前台
PrintWriter out = response.getWriter();
out.print(jsonObj);
out.close();
}
我们将获取的所有信息保存在 data.properties 中的auth_company 变量中。同时为了使用方便,在单独保存下permanent_code 和 corpid
再次运行项目,通过postman访问:
成功获取到access_token和permanent_code以及授权企业的信息:
data.properties也写入成功:
注意一:企业微信的token都有效期,一般都是7200ms,而程序并未做过期判断,所以如果像suite_access_token过期了,请手动重新请求一次!
注意二:auth_code只能用一次,需将如果要再次获取access_token需使用3.2的方法。
3.2、 通过永久授权码获取access_token
这里的所需的两个参数都是在3.1获取的: auth_corpid 和 permanent_code:
/*
* 获取企业凭证 access_token
* 请求地址: https://qyapi.weixin.qq.com/cgi-bin/service/get_corp_token?suite_access_token=SUITE_ACCESS_TOKEN
* 请求方式: POST
* @parm1 auth_corpid 授权方corpid
* @parm2 永久授权码permanent_code,getPermanentcode方法获取
*/
@RequestMapping(value = "accesstoken.do" ,method = RequestMethod.POST)
public void getAccessToken(HttpServletRequest request, HttpServletResponse response) throws JSONException, IOException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_corp_token?suite_access_token=";
String suite_access_token = PropertiesUtil.getProperty("suite_access_token");
String auth_corpid = PropertiesUtil.getProperty("auth_corpid");
String permanent_code = PropertiesUtil.getProperty("permanent_code");
url += suite_access_token;
String auth_code = PropertiesUtil.getProperty("auth_code");
JSONObject jsonParms = new JSONObject();
jsonParms.put("auth_corpid", auth_corpid);
jsonParms.put("permanent_code", permanent_code);
JSONObject jsonObj = HttpHelper.doPost(url,jsonParms);
PropertiesUtil.setProperty("access_token", (String) jsonObj.get("access_token"));
// 将信息发送至前台
PrintWriter out = response.getWriter();
out.print(jsonObj);
out.close();
}
运行项目,postman访问:
后台成功打印:
4、设置授权配置
在安装应用时,需要先进行授权。
先要通过获取预授权码接口获取预授权码,再通过预授权码进行授权。
4.1、获取预授权码
/**
* 获取预授权码pre_auth_code
*
* 请求地址: https://qyapi.weixin.qq.com/cgi-bin/service/get_pre_auth_code?suite_access_token=SUITE_ACCESS_TOKEN
* 请求方式: GET
* @parm1 三方应用suite_access_token,由计算出getSuiteToken
*/
@RequestMapping(value = "pre_auth.do" ,method = RequestMethod.POST)
public void getPreAuthCode(HttpServletRequest request, HttpServletResponse response) throws JSONException, IOException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_pre_auth_code?suite_access_token=";
String suite_access_token = PropertiesUtil.getProperty("suite_access_token");
url += suite_access_token;
JSONObject jsonObj = HttpHelper.doGet(url);
PropertiesUtil.setProperty("pre_auth_code", (String) jsonObj.get("pre_auth_code"));
// 将信息发送至前台
PrintWriter out = response.getWriter();
out.print(jsonObj);
out.close();
}
重启并用postman访问:
获取成功!
4.2、 进行授权
有了pre_auth_code 和suite_access_token就可以进行授权配置了。
因为我们这里是安装测试应用,所以还一个重要参数auth_type需配置为1:
/**
* 设置授权配置AuthCode
*
* 说明:需要对应用进行授权配置才能被企业授权安装
* 请求地址: https://qyapi.weixin.qq.com/cgi-bin/service/set_session_info?suite_access_token=SUITE_ACCESS_TOKEN
* 请求方式: POST
* @parm1 三方应用suite_access_token,由计算出getSuiteToken
* @parm2 预授权码pre_auth_code,由计算出getPreAuthCode
* @parm3 auth_type,授权类型:0 正式授权, 1 测试授权。 默认值为0
*/
@RequestMapping(value = "setsessioninfo.do" ,method = RequestMethod.POST)
public void setSessionInfo(HttpServletRequest request, HttpServletResponse response) throws JSONException, IOException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/service/set_session_info?suite_access_token=";
String suite_access_token = PropertiesUtil.getProperty("suite_access_token");
url += suite_access_token;
JSONObject jsonParmsSon = new JSONObject();
jsonParmsSon.put("auth_type",1);
JSONObject jsonParms = new JSONObject();
jsonParms.put("pre_auth_code", PropertiesUtil.getProperty("pre_auth_code"));
jsonParms.put("session_info", jsonParmsSon);
JSONObject jsonObj = HttpHelper.doPost(url,jsonParms);
// 将信息发送至前台
PrintWriter out = response.getWriter();
out.print(jsonObj);
out.close();
}
重启项目并通过postman访问:
授权成功!
接下来就可以进行安装测试了:
总结
自此,企业微信三方开发的三个重要token已经成功获取!
下一篇我们将从企业微信登录入手开始开发。