python项目对接钉钉SDK的实现


Posted in Python onJuly 15, 2019

 钉钉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
可以后台启动

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

Python 相关文章推荐
Python简单日志处理类分享
Feb 14 Python
Python中使用第三方库xlrd来写入Excel文件示例
Apr 05 Python
微信跳一跳python自动代码解读1.0
Jan 12 Python
对python 合并 累加两个dict的实例详解
Jan 21 Python
python opencv 批量改变图片的尺寸大小的方法
Jun 28 Python
python判断一个对象是否可迭代的例子
Jul 22 Python
python 已知一个字符,在一个list中找出近似值或相似值实现模糊匹配
Feb 29 Python
Python socket连接中的粘包、精确传输问题实例分析
Mar 24 Python
django使用channels实现通信的示例
Oct 19 Python
pandas将list数据拆分成行或列的实现
Dec 13 Python
利用python进行数据加载
Jun 20 Python
Python面向对象之内置函数相关知识总结
Jun 24 Python
用Python识别人脸,人种等各种信息
Jul 15 #Python
django中账号密码验证登陆功能的实现方法
Jul 15 #Python
python tkinter窗口最大化的实现
Jul 15 #Python
在pycharm下设置自己的个性模版方法
Jul 15 #Python
Pycharm新建模板默认添加个人信息的实例
Jul 15 #Python
在python中将list分段并保存为array类型的方法
Jul 15 #Python
详解Python对JSON中的特殊类型进行Encoder
Jul 15 #Python
You might like
php chr() ord()中文截取乱码问题解决方法
2008/09/08 PHP
php 动态添加记录
2009/03/10 PHP
Ajax+PHP 边学边练之四 表单
2009/11/27 PHP
PHP 截取字符串专题集合
2010/08/19 PHP
PHP二维数组的去重问题解析
2011/07/17 PHP
写一段简单的PHP建立文件夹代码
2015/01/06 PHP
php保存信息到当前Session的方法
2015/03/16 PHP
PHP中SQL查询语句的id=%d解释(推荐)
2016/12/10 PHP
详解PHP防止盗链防止迅雷下载的方法
2017/04/26 PHP
繁简字转换功能
2006/07/19 Javascript
前端开发的开始---基于面向对象的Ajax类
2010/09/17 Javascript
JavaScript中string对象
2015/06/12 Javascript
聊一聊JS中this的指向问题
2016/06/17 Javascript
微信小程序使用audio组件播放音乐功能示例【附源码下载】
2017/12/08 Javascript
使用 vue-i18n 切换中英文效果
2018/05/23 Javascript
vue中锚点的三种方法
2018/07/06 Javascript
js实现倒计时器自定义时间和暂停
2019/02/25 Javascript
Element Rate 评分的使用方法
2020/07/27 Javascript
[28:07]完美世界DOTA2联赛PWL S3 Phoenix vs INK ICE 第二场 12.13
2020/12/17 DOTA
Python Tkinter简单布局实例教程
2014/09/03 Python
对python修改xml文件的节点值方法详解
2018/12/24 Python
Python设计模式之代理模式实例详解
2019/01/19 Python
python Tkinter版学生管理系统
2019/02/20 Python
python Django 创建应用过程图示详解
2019/07/29 Python
基于Python实现拆分和合并GIF动态图
2019/10/22 Python
GUESS盖尔斯法国官网:美国时尚品牌
2016/09/23 全球购物
英国天然保健品网站:Simply Supplements
2017/03/22 全球购物
德国最大的婴儿用品网上商店:Kidsroom.de(支持中文)
2020/09/02 全球购物
成都思必达公司C#程序员招聘面试题
2013/06/26 面试题
优秀三好学生事迹材料
2014/08/31 职场文书
小学工作总结2015
2015/05/04 职场文书
立案决定书范文
2015/06/24 职场文书
2015质检员个人年终工作总结
2015/10/23 职场文书
2016党员干部廉政准则学习心得体会
2016/01/20 职场文书
一文搞懂如何实现Go 超时控制
2021/03/30 Python
Golang MatrixOne使用介绍和汇编语法
2022/04/19 Golang