python如何使用sdk_python项目对接钉钉SDK的实现

钉钉SDK

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

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

准备好下面几个参数

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. 流程

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

2019071515104859.jpg

2019071515104860.jpg

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

解决方法:

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

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

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

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);

}

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

2019071515104861.jpg

拿到code请求后端接口

// 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)

}

})

后端用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

2019071515104862.jpg

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

1.注册事件

2019071515104863.jpg

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

2019071515104864.jpg

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

json数据包含这些参数

2019071515104865.jpg

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

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

2019071515104966.jpg

钉钉的文档看不太懂…

2019071515104967.jpg

百度搜了下 发现有人自己封装了这个库,我看了下名字XXXcrypto,crypto这个单词好像在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的源码

2019071515104968.jpg

在开始定义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

可以后台启动

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值