钉钉的回调事件列表:
user_add_org : 通讯录用户增加
user_modify_org : 通讯录用户更改
user_leave_org : 通讯录用户离职
org_admin_add :通讯录用户被设为管理员
org_admin_remove :通讯录用户被取消设置管理员
org_dept_create : 通讯录企业部门创建
org_dept_modify : 通讯录企业部门修改
org_dept_remove : 通讯录企业部门删除
org_remove : 企业被解散
org_change : 企业信息发生变更
label_user_change :员工角色信息发生变更
label_conf_add:增加角色或者角色组
label_conf_del:删除角色或者角色组
label_conf_modify:修改角色或者角色组
另外,在开发第三方企业应用时,通过回调URL推送suite_ticket。
所有的回调事件发生的时候会向URL POST数据,数据需要解密,解密后为
{
"SuiteKey": "suitexxxxxx",
"EventType": "suite_ticket ",
"TimeStamp": 1234456,
"SuiteTicket": "adsadsad"
}
然后所有的回调都需要向服务器返回经过加密的字符串'seccess'的json数据,
{
"msg_signature":"111108bb8e6dbce3c9671d6fdb69d15066227608",
"timestamp":"1783610513",
"nonce":"123456",
"encrypt":"1ojQf0NSvw2WPvW7LijxS8UvISr8pdDP+rXpPbcLGOmIBNbWetRg7IP0vdhVgkVwSoZBJeQwY2zhROsJq/HJ+q6tp1qhl9L1+ccC9ZjKs1wV5bmA9NoAWQiZ+7MpzQVq+j74rJQljdVyBdI/dGOvsnBSCxCVW0ISWX0vn9lYTuuHSoaxwCGylH9xRhYHL9bRDskBc7bO0FseHQQasdfghjkl" // "Random"字段的加密数据
}
下面介绍一下字符串的加解密。
https://open-doc.dingtalk.com/microapp/faquestions/ltr370,这个是文档给出的加解密的方法。
然后就是使用python将整个过程实现。
from base64 import b64encode, b64decode
from Crypto.Cipher import AES
from hashlib import sha1
import struct, random,
class prpcrypt():
def __init__(self, key):
self.key = key
self.mode = AES.MODE_CBC
self.Aec_key = b64decode(self.key + '=')
def encrypt(self, text, key):
# 加密
rand_txt = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'
txt = ''.join(random.sample(rand_txt, 16))
text_len = struct.pack('!i', len(text)).decode()
crypto = AES.new(self.Aec_key, self.mode, self.key[:16])
text = txt + text_len + text + key
text = text + (16-len(text) % 16)*chr(16-len(text)%16)
ciphertext = crypto.encrypt(text)
return b64encode(ciphertext).decode().strip()
def decrypt(self, text):
# 解密
crypto = AES.new(self.Aec_key, self.mode, self.key[:16])
plain_text = crypto.decrypt(b64decode(text))
raw = plain_text.rstrip(b'\0')
length = struct.unpack('!i', raw[16:20])[0]
return raw[20:20+length].decode().strip()
def gen_signature(self, token, timestamp, nonce, encrypt):
# 获取签名
sign = sha1(''.join(sorted([token, timestamp, nonce, encrypt])).encode())
return sign.hexdigest()
然后就是拿到POST的数据然后返回'success'
@csrf_exempt
def callback(request):
token = 'token' # 加解密需要用到的token
aes_key = 'aes_key' # 数据加密的密钥
suiteKey = 'suiteKey'
suiteSecret = 'suiteSecret'
crypt = prpcrypt(aes_key)
signature = request.GET.get('signature')
timestamp = request.GET.get('timestamp')
nonce = request.GET.get('nonce')
msg_encrypt = json.loads(request.body, encoding='utf-8').get('encrypt')
msg_signature = crypt.gen_signature(token, timestamp, nonce, msg_encrypt)
if signature == msg_signature:
data = json.loads(crypt.decrypt(text=msg_encrypt))
EventType = data.get('EventType')
(根据EventType对事件作处理)...
# encrypt = crypt.encrypt("success", suiteKey) 第三方企业应用
encrypt = crypt.encrypt("success", corpId) 企业内部应用
result = json.dumps(dict(
encrypt=encrypt,
msg_signature=crypt.gen_signature(token, timestamp, nonce, encrypt),
nonce=nonce,
timeStamp=timestamp,
))
return HttpResponse(result)