当我们对接钉钉第三方服务商应用,也叫ISV应用,就是企业微信的第三方服务商应用。有以下几个要点步骤。

第一章 服务商入驻

认证产品方案服务商https://partner.dingtalk.com/indexReource#/isv_service/service_info1、打开上面的网址,点击【去认证】。注意,这里一定要使用管理员的帐号去操作,否则可能看不到网页或提示无权限。页面认证的图大概如下。这里也是需要营业执照和公司的公章。

2、这里的第一步非常的重要,如果第一步没有完成,后面的步骤是无法看到的,比如新建第三方应用等操作。

3、如果上面的认证没有完成,技术人员可以先去认证成为开发者,输入自己相关的信息,例如手机号等。

第二章 应用配置

钉钉企业应用列表https://open-dev.dingtalk.com/fe/app#/corp/app1、打开上面的网页,进入后,点击【应用开发】,选择【第三方企业应用】。可以参照下图。

2、选择【第三方企业应用】,然后点击右边的创建应用。

3、新建的时候,选择【H5微应用】,这样既可以在PC端也可以在手机端,本文只是DEMO,所以选择的是JSP,前后端一起的。

4、也可以参照下面的教程,都是填写一些基本信息。

钉钉第三方企业应用开发快速入门文章目录钉钉第三方企业应用开发快速入门1、创建小程序1.1. 登录开发者后台1.2. 填写基础信息1.3. 查看应用信息2、设置安全域名3、设置接口权限4、开发管理(创建回调)5、下载源码6、设置与修改源码6.1. 服务器端6.1.1. 配置代码6.2. 前端下载6.2.1. 修改前端配置7、添加体验组织并开通应用8、推送Ticket9、项目关联钉钉应用钉钉第三方企业应用开发快速入门1、创建小程序1.1. 登录开发者后台登录钉钉开发者后台,选择应用开发-第三方企业应用-小程序,点击创建应用。1.https://blog.csdn.net/a309220728/article/details/120704548

第三章 应用开发

1、进入到具体的开发,可以参照下面的博文,比较全面。

2、代码参照地址,记得配置IP白名单,这里叫出口IP配置,不然调用接口提示没有权限。

出口IP配置官网文档在创建第三方企业应用后,需要完成基础配置,例如服务器出口IP并且要指定数据推送方式。https://open.dingtalk.com/document/isv/basic-configuration

钉钉H5微应用开发,服务端示例代码https://gitee.com/lne/ding-server#https://gitee.com/link?target=https%3A%2F%2Fwww.cnblogs.com%2Fapplerosa%2Fp%2F11509512.html3、该代码对应的操作图文教程,如下:

钉钉H5微应用开发,服务端示例代码-图文教程钉钉第三方企业/服务提供商的小程序/微应用开发,实现授权,回调,响应下单,用户免登等基础功能的教程说明;https://www.cnblogs.com/applerosa/p/11509512.html4、参照上面的教程后,基本的suit推送,登录都是可以的,为了后续的上架,我们还需要对现有的功能进行扩展。钉钉官网要求ISV应用上架必须具备的改造。

改造1,通讯录加密,因为后续选择价格便宜的计算巢方式上架。官方给出的教程地址如下:

通讯录加密 - 钉钉开放平台本文档介绍了通讯录加密的操作流程。https://open.dingtalk.com/document/isv/address-book-encryption1、这里需要注意,不管自己的代码逻辑有没有用到通讯录的(用户名称、用户职位、部门名称)这三个字段,接入的代码必须要有。

2、我这里多赘述一下教程。首先我们需要把自己的index页面的地址按照下面的示例,改造出来。最终的效果就是最下面的一长串一样,中间的都不用改。

3、前端页面引入 open-data SDK,在页面中引入以下SDK。

<!-- 注意,这行引入,必须放入到整个页面的所有JS的第一行 -->
<script src="https://auth.dingtalk.com/opendata-1.1.0.js"></script>

4、如下图所示,还有一个要注意的点就是,页面要设置viewport,不然有输入框的页面,在获得焦点后,移动端页面会被放大,这个要注意。还有,下面的一堆JS,都是【安全与监控】-【监控中心】页面复制而来的代码,每个JSP或HTML的页面必须添加,用于监控,不然监控不到数据,后续是无法上架的。

5、前端页面加载 open-data 中的数据。在页面初始化时,需要调用 DTOpenData.init 方法初始化SDK,入参是开通应用企业的corpId。该方法会返回一个boolean值,标识初始化成功或失败。如果初始化失败,一般说明当前用户未登录,需要自动跳转到上面提到的“统一登录”的url进行登录操作。

<script>if (window.DTOpenData.init('$CORPID$')) {// 入参是开通应用企业的corpId// SDK初始化成功,继续执行页面逻辑} else {// 说明当前用户未登录,需要跳转到钉钉统一登录window.location.href = '$统一登录链接url$';}
</script>

6、大概的意思就是,你原来是直接在自己的onload事件里面调用了登录接口,现在把那个登录接口放在这个if里面就可以了。可以参照下图

7、如果在PC上开发,模拟手机端,console控制台会报错,自己把它注释掉就行。或者如下图所示,如果它检测不到自己的环境,就会输出文字【这不是钉钉的环境,报错啦】,而不是不错。

 8、pom中依赖的jar。

<!--      dingtalk第三方企业应用     --><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.1</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.4.4</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId><version>4.3.5</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.4</version></dependency><dependency><groupId>com.aliyun</groupId><artifactId>alibaba-dingtalk-service-sdk</artifactId><version>2.0.0</version></dependency><dependency><groupId>com.aliyun</groupId><artifactId>dingtalk</artifactId><version>1.3.77</version><scope>system</scope><systemPath>${pom.basedir}/lib/dingtalk-1.3.77.jar</systemPath></dependency><dependency><groupId>com.aliyun</groupId><artifactId>dingtalk-shaded</artifactId><version>1.3.77</version><scope>system</scope><systemPath>${pom.basedir}/lib/dingtalk-1.3.77-shaded.jar</systemPath></dependency>

9、pom中build的配置

<build><finalName>dingtalkd3f</finalName><plugins><!-- 指定编译java版本 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><!-- mvn jar 打包 --><!-- 必须指定1.4.2.RELEASE启动,否则jsp页面无法访问 --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>1.4.2.RELEASE</version><configuration><mainClass>cn.renkai721.Dingtalkd3fApplication</mainClass><!-- 包含本地自己引入的jar--><includeSystemScope>true</includeSystemScope></configuration></plugin></plugins><resources><resource><directory>src/main/java</directory><includes><include>**/**</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><!-- 加载resources下所有的文件,配置文件和资源文件--><includes><include>**/**</include></includes><filtering>false</filtering></resource><resource><directory>src/main/webapp</directory><!-- 如果不配置,jsp无法访问 --><targetPath>META-INF/resources</targetPath><includes><include>**/**</include></includes><filtering>false</filtering></resource><resource><directory>lib</directory><includes><include>**/*.jar</include></includes></resource></resources></build>

10,系统用到的【dingtalk-1.3.77.jar】和【dingtalk-1.3.77-shaded.jar】,阿里官网nexus下载的地址如下,

alibaba Nexus jar包下载https://s01.oss.sonatype.org/?spm=ding_open_doc.document.0.0.5283b670U93ous#nexus-search;quick~dingtalk网站打开较慢,多等待,多刷新即可。

11、核心加解密的时候,使用的参数如下

@PostMapping(value = "/dingCallback")
public Object dingCallback(@RequestParam(value = "signature") String signature,@RequestParam(value = "timestamp") Long timestamp,@RequestParam(value = "nonce") String nonce,@RequestBody(required = false) JSONObject body,HttpServletRequest request) throws DingTalkEncryptException {log.info("接收d3f post请求:[signature=[{}], timestamp=[{}], nonce=[{}] ]",signature, timestamp, nonce);// 这里的token是登录管理后台-第三方企业应用-应用详情-应用功能-事件与回调// id 说明:// 1、开发者后台配置的订阅事件为应用级事件推送,//      此时OWNER_KEY为应用的APP_KEY(企业内部应用)或SUITE_KEY(三方应用)。// 2、调用订阅事件接口订阅的事件为企业级事件推送,//      此时OWNER_KEY为:企业的CORP_ID(企业内部应用)或SUITE_KEY(三方应用)DingTalkEncryptor dingTalkEncryptor = new DingTalkEncryptor(MsgUtil.val("dingtalkd3f.token"),MsgUtil.val("dingtalkd3f.aesKey"),MsgUtil.val("dingtalkd3f.suiteKey"));try {// 从post请求的body中获取回调信息的加密数据进行解密处理String encrypt = body.getString("encrypt");String plainText = dingTalkEncryptor.getDecryptMsg(signature, timestamp.toString(), nonce, encrypt);JSONObject callBackContent = JSON.parseObject(plainText);log.info("plainText={}", plainText);// 根据回调事件类型做不同的业务处理String eventType = callBackContent.getString("EventType");if ("check_create_suite_url".equalsIgnoreCase(eventType)) {// 创建应用,验证回调URL创建有效事件(第一次保存回调URL之前)log.info("[callback] 检查钉钉向回调URL POST数据解密后是否成功 plainText={}",plainText);// 返回success的加密信息表示回调处理成功return dingTalkEncryptor.getEncryptedMap("success", timestamp, nonce);} else if ("check_update_suite_url".equalsIgnoreCase(eventType)) {log.info("验证更新回调URL有效性: " + plainText);return dingTalkEncryptor.getEncryptedMap("success", timestamp, nonce);} else if ("tmp_auth_code".equalsIgnoreCase(eventType)) {// 授权开通// 本事件应用应该异步进行授权开通企业的初始化,目的是尽最大努力快速返回给钉钉服务端。用以提升企业管理员开通应用体验// 即使本接口没有收到数据或者收到事件后处理初始化失败都可以后续再用户试用应用时从前端获取到corpId并拉取授权企业信息,进而初始化开通及企业。log.info("[callback] 企业开通授权 plainText={}", plainText);Boolean active = d3fService.suiteActive(callBackContent);return dingTalkEncryptor.getEncryptedMap(active ? "success" : "active_failure", timestamp, nonce);} else if ("suite_relieve".equalsIgnoreCase(eventType)) {log.info("[callback] 企业解除授权 plainText={}", plainText);return dingTalkEncryptor.getEncryptedMap("success", timestamp, nonce);} else if ("check_url".equalsIgnoreCase(eventType)) {log.info("[callback] 应用功能-事件与回调-回调请求地址-验证有效性 plainText={}", plainText);return dingTalkEncryptor.getEncryptedMap("success", timestamp, nonce);}else if ("sync_http_push_high".equalsIgnoreCase(eventType)) {DingtalkEventTypeParent dingtalkEventTypeParent =JSONObject.parseObject(plainText,DingtalkEventTypeParent.class);if(dingtalkEventTypeParent.getBizData() != null && dingtalkEventTypeParent.getBizData().size() > 0){for(DingtalkBizDataParent obj:dingtalkEventTypeParent.getBizData()){String corp_id = obj.getCorp_id();try{// 一个事件错误继续执行下一个事件,不中断if(MyConstants.NUM_2 == obj.getBiz_type().intValue()){// 当biz_type=2时,数据为第三方企业应用的票据suiteTicket最新状态。DingtalkBizData2 dingtalkBizDataSuitTicket =JSONObject.parseObject(obj.getBiz_data(), DingtalkBizData2.class);if("suite_ticket".equalsIgnoreCase(dingtalkBizDataSuitTicket.getSyncAction())){// suite_ticket用于用签名形式生成accessToken(访问钉钉服务端的凭证),需要保存到应用的db。// 钉钉会定期向本callback url推送suite_ticket新值用以提升安全性。// 应用在获取到新的时值时,保存db成功后,返回给钉钉success加密串(如本demo的return)// 钉钉开放平台会向应用的回调URL推送的suite_ticket(约5个小时推送一次)String suite_ticket_value = dingtalkBizDataSuitTicket.getSuiteTicket();log.info("[callback] 验证回调地址有效性 suite_ticket={}", suite_ticket_value);String suiteId = MsgUtil.val("dingtalkd3f.suiteId");}}else if(MyConstants.NUM_4 == obj.getBiz_type().intValue()){// 当biz_type=4时,数据为企业授权应用的最新状态。// org_suite_auth,org_suite_change两个事件都表示企业对于第三方企业应用的授权信息,需要等同处理,在很短时间内发生的两个事件,有可能会覆盖,保证只给出最新的授权信息// org_suite_auth:表示企业授权第三方企业应用// org_suite_change:表示企业变更授权范围// org_suite_relieve:表示企业解除授权
String suit_id=obj.getBiz_id();String userId = dingtalkBizData4.getAuth_user_info().getUserId();String full_corp_name = dingtalkBizData4.getAuth_corp_info().getFull_corp_name();String corp_name = dingtalkBizData4.getAuth_corp_info().getCorp_name();String inviteCode = dingtalkBizData4.getAuth_corp_info().getInviteCode();Integer agentid = dingtalkBizData4.getAuth_info().getAgent().get(0).getAgentid();String permanent_code = dingtalkBizData4.getPermanent_code();log.info("第三方应用授权,变更,解除,obj={}",obj);DingtalkBizData4 dingtalkBizData4 =JSONObject.parseObject(obj.getBiz_data(), DingtalkBizData4.class);if("org_suite_auth".equalsIgnoreCase(dingtalkBizData4.getSyncAction())){log.info("第三方应用授权 dingtalkBizData4={}",dingtalkBizData4);}else if("org_suite_change".equalsIgnoreCase(dingtalkBizData4.getSyncAction())){// 添加新人或删除人了log.info("修改应用可见范围,公司名称={},corp_id={}",user_corp_name,corp_id);DingtalkBizData4AuthOrgScopes auth_org_scopes = dingtalkBizData4.getAuth_scope().getAuth_org_scopes();String[] users = auth_org_scopes.getAuthed_user();}else if("org_suite_relieve".equalsIgnoreCase(dingtalkBizData4.getSyncAction())){log.info("解除第三方应用 org_suite_relieve corp_id={}",corp_id);}}else if(MyConstants.NUM_7 == obj.getBiz_type().intValue()){DingtalkBizData7 dingtalkBizData7 =JSONObject.parseObject(obj.getBiz_data(), DingtalkBizData7.class);if("org_micro_app_stop".equalsIgnoreCase(dingtalkBizData7.getSyncAction())){// 停用log.info("客户停用,corp_id={}",corp_id);}else if("org_micro_app_restore".equalsIgnoreCase(dingtalkBizData7.getSyncAction())){// 启用log.info("客户启用,corp_id={}",corp_id);}}}catch (Exception e){e.printStackTrace();log.error("error e={}",e);}}return dingTalkEncryptor.getEncryptedMap("success", timestamp, nonce);}}} catch (Exception e) {log.error("process callback fail e={}",e);}return dingTalkEncryptor.getEncryptedMap("failure", timestamp, nonce);
}

12、官网的事件订阅地址

配置事件订阅 - 钉钉开放平台钉钉会向应用推送订阅的事件,例如部门变更、签到通知、打卡通知等。通过订阅这些事件,可以更好地与钉钉集成。你只需告诉钉钉当某个事件发生时,钉钉需要推送消息到哪个URL,钉钉会以HTTPhttps://open.dingtalk.com/document/orgapp-server/configure-event-subcription13、API Explorer,这个工具可以很快的找到自己需要的API,然后可以点击测试,也可以很快的导航到对应的DOC文档中去,很实用。记得进入页面后选择【第三方企业应用】。API Explorer企业注册并上传企业通讯录后,手机端随时随地找人不再难,与同事和客户免费电话多方通话,重要事DING一下电话使命必达。还可以申请免费企业云邮箱和请假系统、财务报销系统,以及自有OA的移动化管理使用https://open-dev.dingtalk.com/apiExplorer?spm=ding_open_doc.document.0.0.717f722fyXp9c3#/?devType=isv&api=oauth2_1.0%23CreateJsapiTicket

14、钉钉的授权事件,也就是需要解密知道当前监听事件的消息是哪种操作,请看下面的文档。

授权事件 - 钉钉开放平台本文介绍了授权的RDS和SyncHTTP推送的数据格式。https://open.dingtalk.com/document/isvapp-server/authorization-event15、这些事件中biz_type=2,4的时候,关键信息,一定要保存下来。比如2的时候,需要保存【suite_ticket】,接收到【tmp_auth_code】时候,需要激活应用。接收到4的时候,关键信息一定要保存下来,后面会用到agentId,等。

/*** 激活应用授权* tmp_auth_code*/
public Boolean suiteActive(JSONObject activeNode) throws ApiException {Boolean isActive = false;String corpId = activeNode.get("AuthCorpId").toString();String tempAuthCode = activeNode.get("AuthCode").toString();String suiteToken = this.getSuiteToken();String permanentCode = this.getPermanentCode(suiteToken, tempAuthCode);if (!com.alibaba.druid.util.StringUtils.isEmpty(permanentCode)) {isActive = this.activateSuite(suiteToken, corpId, permanentCode);if (isActive) {this.getCorpAuthInfoByActive(corpId);}} else {log.error("获取永久授权码出错");}return isActive;
}public String getSuiteToken() {String url_suite_token = "https://oapi.dingtalk.com/service/get_suite_token";DingTalkClient client = new DefaultDingTalkClient(url_suite_token);OapiServiceGetSuiteTokenRequest request = new OapiServiceGetSuiteTokenRequest();request.setSuiteKey(MsgUtil.val("dingtalkd3f.suiteKey"));request.setSuiteSecret(MsgUtil.val("dingtalkd3f.suiteSecret"));String suite_ticket = this.get_suite_ticket();request.setSuiteTicket(suite_ticket);String suiteId = MsgUtil.val("dingtalkd3f.suiteId");RBucket<String> idBucket = redissonClient.getBucket(QywxProperties.dingtalk_suite_token+suiteId);String accessToken = idBucket.get();log.info("accessToken={}",accessToken);if(com.alibaba.druid.util.StringUtils.isEmpty(accessToken)){try {OapiServiceGetSuiteTokenResponse response = client.execute(request);accessToken = response != null ? response.getSuiteAccessToken() : "";idBucket.set(accessToken,response.getExpiresIn(),TimeUnit.SECONDS);} catch (ApiException e) {e.printStackTrace();log.error("获取第三方应用凭证suite_access_token出错, code={}, msg={}", e.getErrCode(), e.getErrMsg());}log.info("获取第三方应用凭证suite_access_token, accessToken={}", accessToken);}return accessToken;}public String getPermanentCode(String suiteAccessToken, String tempCode) {String url_permanent_code = "https://oapi.dingtalk.com/service/get_permanent_code";StringBuilder url = new StringBuilder();url.append(url_permanent_code);url.append("?suite_access_token=").append(suiteAccessToken);DingTalkClient client = new DefaultDingTalkClient(url.toString());OapiServiceGetPermanentCodeRequest req = new OapiServiceGetPermanentCodeRequest();req.setTmpAuthCode(tempCode);String permanentCode = "";try {OapiServiceGetPermanentCodeResponse rsp = client.execute(req);permanentCode = (rsp != null ? rsp.getPermanentCode() : "");} catch (ApiException e) {e.printStackTrace();log.error("获取永久授权码出错, tempCode={}, code={}, msg={}", tempCode, e.getErrCode(), e.getErrMsg());}log.info("获取永久授权码, tempCode={}, permanentCode={}", tempCode, permanentCode);return permanentCode;}public Boolean activateSuite(String suiteAccessToken, String corpId, String permanentCode) {String url_activate_suite = "https://oapi.dingtalk.com/service/activate_suite";StringBuilder url = new StringBuilder();url.append(url_activate_suite);url.append("?suite_access_token=").append(suiteAccessToken);DingTalkClient client = new DefaultDingTalkClient(url.toString());OapiServiceActivateSuiteRequest req = new OapiServiceActivateSuiteRequest();req.setSuiteKey(MsgUtil.val("dingtalkd3f.suiteKey"));req.setAuthCorpid(corpId);req.setPermanentCode(permanentCode);boolean isActive = false;try {OapiServiceActivateSuiteResponse rsp = client.execute(req);isActive = rsp.getErrmsg().equals("ok");} catch (ApiException e) {e.printStackTrace();log.error("激活应用的企业授权出错, corpId={}, permanentCode={}, code={}, msg={}", corpId, permanentCode, e.getErrCode(), e.getErrMsg());}log.debug("激活应用的企业授权, corpId={}, permanentCode={}, isActive={}", corpId, permanentCode, isActive);return isActive;}public void getCorpAuthInfoByActive(String corpId) {String corpToken = get_access_token(corpId);log.info("获取企业授权凭证:{}", corpId);JsonNode corpAuthInfo = getCorpAuthInfo(corpId);log.info("获取企业信息详情:{}", corpAuthInfo);}public JsonNode getCorpAuthInfo(String corpId) {String url_get_auth_info = "https://oapi.dingtalk.com/service/get_auth_info";DingTalkClient client = new DefaultDingTalkClient(url_get_auth_info);OapiServiceGetAuthInfoRequest req = new OapiServiceGetAuthInfoRequest();req.setAuthCorpid(corpId);JsonNode result = JsonTool.emptyNode();try {String suite_ticket = this.get_suite_ticket();OapiServiceGetAuthInfoResponse response = client.execute(req,MsgUtil.val("dingtalkd3f.suiteKey"),MsgUtil.val("dingtalkd3f.suiteSecret"),suite_ticket);result = JsonTool.getNode(response);} catch (ApiException e) {log.error("获取企业授权-详情 出错, corpId={}, code={}, msg={}", corpId, e.getErrCode(), e.getErrMsg());}log.info("获取企业授权-详情, corpId={}, auth_result={}", corpId, result);return result;}public String get_access_token(String corp_id) {// 调用服务端API获取应用资源时,需要通过access_token来鉴权调用者身份进行授权String suiteId = MsgUtil.val("dingtalkd3f.suiteId");RBucket<String> idBucket = redissonClient.getBucket(QywxProperties.dingtalk_corp_token+"_"+corp_id+suiteId);String corp_token = idBucket.get();log.info("corp_token={}",corp_token);if(com.alibaba.druid.util.StringUtils.isEmpty(corp_token)){DefaultDingTalkClient client= new DefaultDingTalkClient("https://oapi.dingtalk.com/service/get_corp_token");OapiServiceGetCorpTokenRequest req= new OapiServiceGetCorpTokenRequest();req.setAuthCorpid(corp_id);String suite_ticket = this.get_suite_ticket();OapiServiceGetCorpTokenResponse execute= null;try {execute = client.execute(req,MsgUtil.val("dingtalkd3f.suiteKey"),MsgUtil.val("dingtalkd3f.suiteSecret"),suite_ticket);corp_token = execute.getAccessToken();Long expires_in = execute.getExpiresIn();if(expires_in != null){idBucket.set(corp_token,expires_in, TimeUnit.SECONDS);}else{log.error("corp_token api is error");}} catch (ApiException e) {e.printStackTrace();}}return corp_token;}

16、【部署与发布】-【版本管理与发布】,选择要授权的体验组织,然后点击【授权】,后台应该就会收到授权的事件了,如果授权成功,过一会刷新页面就能看到了,如果确认自己的代码没有问题,前端提示授权失败,或其它的没有展示,都是钉钉自己的问题,过一会再试试就OK了。自己也可以生成二维码,让其它的组织加入进来。

17、到此开发的后台基本完毕。

第四章 应用上架

1、上面开发完毕后,就是上架的流程,这个比较难搞,官方写的不清楚。请按照下面的流程来做。

2、点击【部署与发布】-【应用部署】-部署方式选择,计算巢部署。

3、然后关键的操作来了,一定要使用阿里云超管RAM帐号操作,不是普通的子账号或有权限的人的帐号来操作。然后超管需要绑定自己的钉钉号。操作步骤是,登录阿里云控制台

阿里云控制台首页欢迎登录阿里云,全球领先的云计算及人工智能科技公司,阿里云为200多个国家和地区的企业、开发者和政府机构提供云计算基础服务及解决方案。阿里云云计算、安全、大数据、人工智能、企业应用、物联网等云计算服务。https://home.console.aliyun.com/home/dashboard/ProductAndService然后,点击右上角的小图标,然后选择【安全信息管理】

然后去绑定钉钉帐号,

4、接下来,点击【资源管理】

5、进去以后,主要导入ECS,自己的后台服务器;RDS,自己的数据库,注意代码上线不能使用外网地址,必须使用内网链接地址;SLB负载均衡的机器,如果没有SLB,必须要购买一台。这里的ECS和RDS就不多说了。主要说一下SLB。

6、我们随便找一台有nginx的ECS机器,然后在上面装好nginx,在nginx里面转发到自己的后台服务中去,然后SLB负载这里只配置一个http80的端口和一个https443的端口,注意443必须使用公司以及域名的SSL证书。

7、这样配置好了后,回到钉钉的页面,点击【安全与监控】-【钉钉安全域名】,然后就能看到刚才生成的安全域名了。这时候点击提交,去自己的代码里面把以前自己监听的http地址或自定义域名改成这个域名,注意nginx里面要监听这个安全域名,不然你还是访问不到。

8、把自己的以前配置的页面,首页或后台http push的地址都改成这个安全域名就可以了。至于那个页面中一直显示的出口IP未配置,不用去管。直接去点击自检,然后提交上线,这时候有一堆的文件或截图要弄,需要耐心,一步一步去操作。没有的话去网上找些资料改一改。

9、然后需要【安全验收】,【产品验收】,【稳定性验收】,也可以参照下面的几个官网教程

应用部署 - 钉钉开放平台计算巢为服务商提供了一套环境管理应用,一键云资源与应用诊断,一体化监控事件收集和预警体系https://open.dingtalk.com/document/isv/deploy-applications-1计算巢应用导入资源 - 钉钉开放平台本文档介绍了如何访问计算巢关联应用以及资源导入。https://open.dingtalk.com/document/isv/create-a-compute-nest-application安全准入评估指南 - 钉钉开放平台本文介绍了安全准入指南,包括应用基础信息、安全技术、安全管理和其他钉钉自检评估项的安全准入评估要求。https://open.dingtalk.com/document/operation-specification/security-access-evaluation-guide安全性认证 - 钉钉开放平台本文介绍了安全测试报告相关内容,包括常见问题、安全测试用例、安全测试结果等。https://open.dingtalk.com/document/operation-specification/Security-certification10、上面的【安全准入评估指南 - 钉钉开放平台】和【安全性认证 - 钉钉开放平台】很重要,其中的工作量也很大。

11、到此需要完成的基本差不多,只需要完成对应的指标即可申请上架和付款。其中的ISV上架的保证金是10万元。

12、等待审核。

钉钉第三方服务商应用ISV应用开发及上架教程相关推荐

  1. IOS APP开发:苹果app从开发到上架教程详解

    不少人认为按照目前市场占有率,app开发还是以安卓为主,但不可忽视的是, ios app开发的用户基础还是很庞大的,用户需求也很稳定,市场挖掘潜力还是很客观,进行苹果app开发还是存在很大优势的.今天 ...

  2. 飞书第三方ISV服务商应用开发及上架教程

    第一章 服务商入驻 1.使用管理员登录服务商管理后台 飞书ISV服务商注册地址应用敏捷开发,服务高效入驻.飞书开放平台致力于以先进的协同办公理念和产品助力企业成长,帮助企业打造愉悦高效的专属办公平台. ...

  3. 苹果iOS App上架流程,非iOS开发人员上架教程

    iOS应用上线发布流程一般包含相关证书文件的配置.Xcode的设置.App Store Connect填写App的相关信息.ipa包上传.审核结果以及相关邮件回复.相关证书文件的配置与Xcode的设置 ...

  4. 钉钉JSAPI前端鉴权

    钉钉二次开发分为如下表所示三种类型的开发,只有企业内部应用才需要对JSAPI鉴权. 类型 开发方式 JSAPI鉴权 应用场景 第三方企业应用 E应用开发 不需要 用于发布到钉钉应用市场,供广大用户下载 ...

  5. 钉钉ISV第三方企业应用开发思路

    一.企业开户(数据库:meng)公司表, 充值记录,套餐表, 1. 企业开户(管理员钉钉号入口) 2. 创建1条记录:名称.有效期.DB名称 3. 创建企业系统库的DB,初始化(导入SQL,修改一些默 ...

  6. 钉钉开发第三方H5微应用入门详细教程[ISV][免登流程][授权码][HTTP回调推送][识别用户身份][获取用户信息]...

    转载请注明原文地址:https://www.cnblogs.com/applerosa/p/11509512.html (by lnexin@aliyun.com 世间草木) 此教程注意点: 适用于第 ...

  7. 钉钉api 获取 accesstoken_钉钉开放平台第三方 Python SDK,快速实现钉钉API开发

    dingtalk-sdk 是一个钉钉开放平台的第三方 Python SDK, 实现了 企业内部开发 和 应用服务商(ISV)的 API. 企业内部开发 建议在使用前先阅读 钉钉开放平台文档 消息实体 ...

  8. 钉钉isv应用开发(钉钉isv应用开发注意事项)

    1.创建套件和微应用, 可参考钉钉的开发者文档:https://open-doc.dingtalk.com/docs/doc.htm?treeId=175&articleId=104943&a ...

  9. Java对接钉钉开发第三方H5微应用详细教程

    文章转载自:钉钉开发第三方H5微应用入门详细教程[ISV][免登流程][授权码][HTTP回调推送][识别用户身份][获取用户信息] - 世间草木 - 博客园 (by lnexin@aliyun.co ...

  10. 钉钉 ISV 应用开发的一些心得

    1. 背景 前段时间从前到后完整地做完了一个简单的钉钉上的 ISV 应用 -- 猿活动. 最开始想做这么一个小工具,是想到,平时部门中经常会组织一些分享活动,但是这些分享活动却没有一个比较直观的&qu ...

最新文章

  1. java元婴期(26)----java进阶(mybatis(5)---spring和mybatis整合(重点)逆向工程(会用))
  2. Visual Studio 2010 and .NET Framework 4 Beta 1
  3. 2021巨量引擎母婴行业白皮书
  4. 飞鸽传书举一个小例子
  5. 40.leetcode17_letter_combinations_of_a_phone_number
  6. 百密一疏,防不胜防,细数那些大型数据库建设过程中绕不开的坑
  7. 今天解决了价位没有同步更新的问题
  8. 计算机在经济管理中的应用,现代经济管理中计算机技术的运用
  9. java Cannot find the class file for javax.servlet.http.HttpServletRequest.错误解决
  10. java基础学习(9)堆和栈的区别详解
  11. 中国网络安全行业发展前景及投资战略研究报告(2022-2027年)
  12. Adobe Fireworks CS4 序列号(注册码)
  13. ABAQUS装配节点建模教程
  14. 小程序 tabBar菜单
  15. 机器学习中Bias(偏差)和Variance(方差)
  16. 蓦然回首,灯火阑珊——自考总结
  17. Oracle EBS APP-FND-02901: you don‘t have privilege to any operating unit
  18. OSChina 周四乱弹 —— 下班等通知,我张北华同意后才下班
  19. 如何做Unity手游性能优化的
  20. 快速上手 ClickHouse

热门文章

  1. MyApps接口引擎,打破跨系统间的壁垒
  2. python catia 接口_使用Python在CATIA中创建新产品
  3. java对接modbus rtu协议设备
  4. 介绍一下Win11单独设置耳机音量的方法
  5. C#制作简易屏幕保护
  6. hive三种建表语句
  7. 【新功能】摹客Figma插件功能升级!标注切图效率加倍
  8. rollup函数 和cube函数 的区别?
  9. Android OpenCV 摄像头实时预览
  10. 交换机cad图例_各种弱电系统的CAD图纸,包含图例、大样图、系统图及原理图等...