python项目对接钉钉SDK的实现

作者:宅神kin 时间:2021-09-18 22:21:29 

 钉钉SDK

对接sdk还是遇到不少问题的

钉钉python版SDK文档地址:https://dingtalk-sdk.readthedocs.io/zh_CN/latest/

钉钉官方服务端文档:https://open-doc.dingtalk.com/microapp/serverapi2

为了避免调试出现不必要的参数错误,前期钉钉配置要做好,血和泪的教训😭

准备好下面几个参数


DINGTALK_CORP_ID = "重点:企业应用ID"
# 钉钉微应用
DINGTALK_APP_KEY = "微应用APP_KEY"
DINGTALK_CORP_SECRET = "微应用SERCRET"
# 钉钉移动应用(扫码登录),在移动应用接入菜单里配置
DINGTALK_APP_ID = "移动应用APP_ID"
DINGTALK_APP_SECRET = "移动应用APP_SECRET"
# 钉钉aes加密(随机)
DINGTALK_AES_TOKEN = "43位字符串 a-zA-Z0-9中生成"
DINGTALK_TOKEN = "字符串随便填"

一. 第三方web网站扫码登录1. 流程

钉钉扫码—>判断是否公司员工—>登录

python项目对接钉钉SDK的实现

python项目对接钉钉SDK的实现

关于web系统的两种接入方式,都只能获取到用户的钉钉身份,并不能获取到用户是否在企业中

解决方法:

批量同步钉钉人员信息到数据库,登录后匹配数据库,新进员工通过钉钉回调同步到数据库,回调未生效人工审核后手动更新数据库

由于钉钉开发文档读的不够仔细导致调试频繁出错,所以开发流程我简单说,把细节放大

前端导入钉钉scrpit文件开发扫码页面


<script src="//g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>
<script>
var url="http://erp.vaiwan.com/api/v1.0/ding_test";
var goto = encodeURIComponent('https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=dingoadwjj1iszubeh9rnf&response_type=code&scope=snsapi_login&state=STATE&redirect_uri='+url);
var obj = DDLogin({
  id:"login_container",
  goto: goto,
  style: "border:none;background-color:#FFFFFF;",
  width : "365",
  height: "400"
});

var hanndleMessage = function (event) {
   var origin = event.origin;
   console.log("origin", event.origin);
 //判断是否来自ddLogin扫码事件。
   if( origin == "https://login.dingtalk.com" ) {
     //拿到loginTmpCode后就可以在这里构造跳转链接进行跳转了
     var loginTmpCode = event.data;
     console.log("loginTmpCode", loginTmpCode);
     if(loginTmpCode){
       let uri="https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=dingoadwjj1iszubeh9rnf&response_type=code&scope=snsapi_login&state=STATE&redirect_uri="+url+"&loginTmpCode="+loginTmpCode;
       // 跳转
       location.href = uri;
     }
   }
};

if (typeof window.addEventListener != 'undefined') {
 window.addEventListener('message', hanndleMessage, false);
} else if (typeof window.attachEvent != 'undefined') {
 window.attachEvent('onmessage', hanndleMessage);
}
</script>

配置扫码后跳转页面(就是第一步goto参数里的url),钉钉会自动在跳转页面路由后添加codestate参数

python项目对接钉钉SDK的实现

拿到code请求后端接口


<script src="https://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script>
<script>
 // location.search: "?code=bb42ec66ed5...&state=STATE"
 let code = location.search.split("&")[0].split("=")[1];
 $.ajax({
   type:"post",
   url:'http://erp.vaiwan.com.cn/api/v1.0/getinfo',
   data:{
     "code":code
   },
   success:function(data){
     console.log(data)
   }
 })
</script>

后端用appid和appsecret获取access_token


import requests
from dingtalk.client import SecretClient

class GetInfoByCode(object):
 def __init__(self):
   self.url = "https://oapi.dingtalk.com/sns"

def get_access_token(self):
   resp = requests.get(
     url=self.url + "/gettoken",
     params=dict(appid=DINGTALK_APP_ID, appsecret=DINGTALK_APP_SECRET)
   )
   resp = resp.json()
   return resp["access_token"]

用access_token和code获取用户unionid


def get_persistent_code(self, code, token):
   resp = requests.post(
     url="%s/get_persistent_code?access_token=%s" % (self.url, token),
     json=dict(tmp_auth_code=code),
   )
   resp = resp.json()
   return resp["unionid"]

用unionid换取userid


ding_client = SecretClient(corp_id=DINGTALK_CORP_ID,
              corp_secret=DINGTALK_CORP_SECRET)
# 这块提醒下一定要做缓存,由于我之前没做缓存,超过钉钉使用频率而被限制了,修改下上面那句代码
import redis
from dingtalk.storage.kvstorage import KvStorage

# redis做缓存
redis_ding = redis.StrictRedis(REDIS_HOST, REDIS_PORT, db=0)
# 划重点,因为我是第三方web网站,没有使用E应用,所以我的corp_id填的是微应用的id,而不是企业应用ID(corp_id)
ding_client = SecretClient(
 corp_id=DINGTALK_APP_KEY,
 corp_secret=DINGTALK_CORP_SECRET,
 storage=KvStorage(redis_ding))

userid = ding_client.user.get_userid_by_unionid(unionid)

userid换取user详情


user = ding_client.user.get(userid["userid"])

二. 加解密

应用场景: 钉钉回调

事件流程:注册回调事件—>处理事件内容(新增员工、更新部门等),返回钉钉加密json

python项目对接钉钉SDK的实现

就是说你调用注册事件API,钉钉会给你需要注册的url发送一个post请求,你得按要求返回success,否则注册失败

1.注册事件

python项目对接钉钉SDK的实现

再看看什么是success的加密json数据

python项目对接钉钉SDK的实现

如果你没有看懂的话,很巧 我也看不懂…

json数据包含这些参数

python项目对接钉钉SDK的实现

时间戳和nonce容易拿,问题在于encryptmsg_signature的生成

因为钉钉没有提供python的加解密库,所以看到这块我有点懵

python项目对接钉钉SDK的实现

钉钉的文档看不太懂…

python项目对接钉钉SDK的实现

百度搜了下 发现有人自己封装了这个库,我看了下名字XXXcryptocrypto这个单词好像在sdk里边见过。

看了sdk目录,果然,虽然钉钉sdk虽然没写关于加解密的内容,但是它其实已经封装了这个库

使用


from dingtalk.crypto import DingTalkCrypto

class Crypto(object):
 def __init__(self):
   # 随便填的字符串
   self.token = DINGTALK_TOKEN
   # 自己生成的43位随机字符串
   self.aes_key = DINGTALK_AES_TOKEN
   # 钉钉企业ID
   self.corpid = DINGTALK_APP_ID
   self.crypto = DingTalkCrypto(
     token=self.token,
     encoding_aes_key=self.aes_key,
     corpid_or_suitekey=self.corpid
   )

说明

原本是不需要自己封装的。看dingtalk的源码

python项目对接钉钉SDK的实现

在开始定义ding_client的时候,只需要填参数就可以,经过我反复的调试,发现因为我开发的是企业内部应用-微应用,而不是E应用,所以这里填的corp_id其实是微应用app_key,参数不正确导致后边调试一直返回文本非success错误,为了不与上边填的参数冲突,所以自己封装Crypto类,填写的corp_id是企业应用id

封装好Crypto这个类,就可以调用啦, 先测试返回给钉钉的结果是否正确


from ... import Crypto

class EventCallBack(Resource):
 def __init__(self):
   self.crypto = Crypto().crypto

def post(self):
   # 返回加密success
   result = self.crypto.encrypt_message(
     msg="success",
     nonce="123456",
     timestamp=int(time.time()*1000)
   )
   return result

事情没这么容易结束…

这个post方法你需要对回调事件作出处理而不是仅仅返回success,所以最终需要这样, 对结果进行处理


def post(self):
   po = request.json["encrypt"]
   data = request.values
   # 返回加密success
   result = self.crypto.encrypt_message(
     msg="success",
     nonce="123456",
     timestamp=int(time.time()*1000)
   )
   # 获取到事件及其他信息
   callback = self.crypto.decrypt_encrypt_str(
     encrypt_str=po,
     nonce=data["nonce"],
     timestamp=data["timestamp"],
     signature=data["signature"]
   )
   # demjson可以把字符串转为字典,否则取值失败
   # 安装 pip install demjson
   callback = demjson.decode(callback)
   # 判断事件类型,作出相应回调
   if callback["EventType"] == "user_add_org":
     # 添加员工
     ...
   elif callback["EventType"] == "org_dept_create":
     # 添加部门
     ...
   return result

三. 调试


# 钉钉内网穿透工具,主要作用是方便本地调试需要回调域名的接口
# 地址: https://open-doc.dingtalk.com/microapp/debug/ucof2g
可以后台启动

来源:https://blog.csdn.net/weixin_42042680/article/details/86661387

标签:python,钉钉,SDK
0
投稿

猜你喜欢

  • 在不能中寻找可能 QZONE个性相册设计的始末

    2009-07-13 12:27:00
  • JavaScript 与 ActionScript 3.0 交互的一些问题

    2008-01-27 12:20:00
  • OracleEXP和IMP用法和介绍

    2010-07-28 13:18:00
  • js怎么覆盖原有方法实现重写

    2024-05-09 10:39:22
  • python Django框架实现web端分页呈现数据

    2022-07-03 03:47:14
  • 用python实现监控视频人数统计

    2022-04-03 16:01:31
  • Python聚类算法之基本K均值实例详解

    2023-07-14 12:49:08
  • Python sklearn 中的 make_blobs() 函数示例详解

    2022-07-24 21:45:48
  • NopCommerce架构分析之(五)Model绑定Action参数

    2024-06-05 09:26:43
  • mycat在windows环境下的安装和启动

    2024-01-17 08:07:14
  • 纯CSS Tooltips提示

    2008-10-18 16:01:00
  • python利用os模块编写文件复制功能——copy()函数用法

    2023-01-20 16:11:56
  • Python实现快速保存微信公众号文章中的图片

    2021-02-18 23:03:25
  • 如何让Firefox2和Firefox3在Windows下共存并同时运行?

    2008-06-01 15:50:00
  • php处理json格式数据经典案例总结

    2023-11-21 13:54:42
  • HTML和SEO基础知识:H标签全透视

    2010-09-21 16:45:00
  • JavaScript预解析及相关技巧分析

    2024-04-10 10:57:32
  • php调用百度人脸识别接口查询数据库人脸信息实现验证登录功能

    2024-03-23 13:36:44
  • 一篇文章彻底弄懂Python字符编码

    2021-06-06 18:51:33
  • Dlib+OpenCV深度学习人脸识别的方法示例

    2022-11-08 06:34:42
  • asp之家 网络编程 m.aspxhome.com